Index: xwiki-core/src/test/java/com/xpn/xwiki/doc/XWikiDocumentTest.java =================================================================== --- xwiki-core/src/test/java/com/xpn/xwiki/doc/XWikiDocumentTest.java (revision 22772) +++ xwiki-core/src/test/java/com/xpn/xwiki/doc/XWikiDocumentTest.java (working copy) @@ -724,31 +724,59 @@ public void testRename() throws XWikiException { + //possible ways to write parents, include documents, or make links: + //"name" -----means-----> DOCWIKI+":"+DOCSPACE+"."+input + //"space.name" -means----> DOCWIKI+":"+input + //"database:name" -means-> input.replace(":",":"+DOCSPACE+".") (Not likely to happen much, but it works so it must be supported throughout) + //"database:space.name" (no change) XWikiDocument doc1 = new XWikiDocument(DOCWIKI, DOCSPACE, "Page1"); - doc1.setContent("[[" + DOCWIKI + ":" + DOCSPACE + "." + DOCNAME + "]] [[" + DOCSPACE + "." + DOCNAME + "]] [[" - + DOCNAME + "]]"); + doc1.setContent("[[" + DOCWIKI + ":" + DOCSPACE + "." + DOCNAME + "]] [[someName>>" + + DOCSPACE + "." + DOCNAME + "]] [[" + + DOCNAME + "]] [[" + + DOCWIKI + ":" + DOCNAME + "]]"); doc1.setSyntaxId("xwiki/2.0"); XWikiDocument doc2 = new XWikiDocument("newwikiname", DOCSPACE, "Page2"); - doc2.setContent("[[" + DOCWIKI + ":" + DOCSPACE + "." + DOCNAME + "]]"); + doc2.setContent("[[" + DOCWIKI + ":" + DOCSPACE + "." + DOCNAME + "]] [[" + + DOCWIKI + ":" + DOCNAME + "]]"); doc2.setSyntaxId("xwiki/2.0"); XWikiDocument doc3 = new XWikiDocument("newwikiname", "newspace", "Page3"); doc3.setContent("[[" + DOCWIKI + ":" + DOCSPACE + "." + DOCNAME + "]]"); doc3.setSyntaxId("xwiki/2.0"); + //test to make sure it also drags children along. + XWikiDocument doc4 = new XWikiDocument(DOCWIKI, DOCSPACE, "Page4"); + doc4.setParent(DOCSPACE + "." + DOCNAME); + XWikiDocument doc5 = new XWikiDocument("newwikiname", DOCSPACE, "Page5"); + doc5.setParent(DOCWIKI + ":" + DOCNAME); + XWikiDocument doc6 = new XWikiDocument("newwikiname", "newspace", "Page6"); + doc6.setParent(DOCWIKI + ":" + DOCSPACE + "." + DOCNAME); + this.mockXWiki.stubs().method("copyDocument").will(returnValue(true)); this.mockXWiki.stubs().method("getDocument").with(eq("1"), ANYTHING).will(returnValue(doc1)); this.mockXWiki.stubs().method("getDocument").with(eq("2"), ANYTHING).will(returnValue(doc2)); this.mockXWiki.stubs().method("getDocument").with(eq("3"), ANYTHING).will(returnValue(doc3)); + this.mockXWiki.stubs().method("getDocument").with(eq("4"), ANYTHING).will(returnValue(doc4)); + this.mockXWiki.stubs().method("getDocument").with(eq("5"), ANYTHING).will(returnValue(doc5)); + this.mockXWiki.stubs().method("getDocument").with(eq("6"), ANYTHING).will(returnValue(doc6)); this.mockXWiki.stubs().method("saveDocument").isVoid(); this.mockXWiki.stubs().method("deleteDocument").isVoid(); - this.document.rename("newwikiname:newspace.newpage", Arrays.asList("1", "2", "3"), getContext()); + this.document.rename("newwikiname:newspace.newpage", Arrays.asList("1", "2", "3"), Arrays.asList("4", "5", "6"), getContext()); - assertEquals( - "[[newwikiname:newspace.newpage]] [[newwikiname:newspace.newpage]] [[newwikiname:newspace.newpage]]", doc1 - .getContent()); - assertEquals("[[newspace.newpage]]", doc2.getContent()); + //test links + + assertEquals("[[newwikiname:newspace.newpage]] " + + "[[someName>>newwikiname:newspace.newpage]] " + + "[[newwikiname:newspace.newpage]] " + + "[[newwikiname:newspace.newpage]]", doc1.getContent()); + assertEquals("[[newspace.newpage]] " + + "[[newspace.newpage]]", doc2.getContent()); assertEquals("[[newspace.newpage]]", doc3.getContent()); + + //test parents + assertEquals("newwikiname:newspace.newpage", doc4.getParent()); + assertEquals("newwikiname:newspace.newpage", doc5.getParent()); + assertEquals("newwikiname:newspace.newpage", doc6.getParent()); } /** Index: xwiki-core/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java =================================================================== --- xwiki-core/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java (revision 22772) +++ xwiki-core/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java (working copy) @@ -4001,8 +4001,10 @@ } /** - * Rename the current document and all the backlinks leading to it. See - * {@link #rename(String, java.util.List, com.xpn.xwiki.XWikiContext)} for more details. + * Rename the current document and all the backlinks leading to it. + * Will also change parent field in all documents which list the + * document we are renaming as their parent. See + * {@link #rename(String, java.util.List, java.util.List, com.xpn.xwiki.XWikiContext)} for more details. * * @param newDocumentName the new document name. If the space is not specified then defaults to the current space. * @param context the ubiquitous XWiki Context @@ -4010,10 +4012,27 @@ */ public void rename(String newDocumentName, XWikiContext context) throws XWikiException { - rename(newDocumentName, getBackLinkedPages(context), context); + rename(newDocumentName, getBackLinkedPages(context), this.getChildren(context), context); } /** + * Rename the current document and all the backlinks leading to it. + * Will not change parent field in any documents which list the + * document we are renaming as their parent. See + * {@link #rename(String, java.util.List, java.util.List, com.xpn.xwiki.XWikiContext)} for more details. + * + * @param newDocumentName the new document name. If the space is not specified then defaults to the current space. + * @param backlinkDocumentNames the list of documents to parse and for which links will be modified to point to the + * new renamed document. + * @param context the ubiquitous XWiki Context + * @throws XWikiException in case of an error + */ + public void rename(String newDocumentName, List backlinkDocumentNames, XWikiContext context) throws XWikiException + { + rename(newDocumentName, backlinkDocumentNames, null, context); + } + + /** * Rename the current document and all the links pointing to it in the list of passed backlink documents. The * renaming algorithm takes into account the fact that there are several ways to write a link to a given page and * all those forms need to be renamed. For example the following links all point to the same page: @@ -4022,18 +4041,21 @@ *
  • [Page?param=1]
  • *
  • [currentwiki:Page]
  • *
  • [CurrentSpace.Page]
  • + *
  • [currentwiki:CurrentSpace.Page]
  • * *

    - * Note: links without a space are renamed with the space added. + * Note: links without a space are renamed with the space added and all documents given in childDocumentNames list + * have their parent field set to "currentwiki:CurrentSpace.Page". *

    * * @param newDocumentName the new document name. If the space is not specified then defaults to the current space. * @param backlinkDocumentNames the list of documents to parse and for which links will be modified to point to the * new renamed document. + * @param childDocumentNames the list of documents whose parent field will be set to the new document name. * @param context the ubiquitous XWiki Context * @throws XWikiException in case of an error */ - public void rename(String newDocumentName, List backlinkDocumentNames, XWikiContext context) + public void rename(String newDocumentName, List backlinkDocumentNames, List childDocumentNames, XWikiContext context) throws XWikiException { // TODO: Do all this in a single DB transaction as otherwise the state will be unknown if @@ -4063,17 +4085,35 @@ return; } + //grab the xwiki object, it gets used a few times. + com.xpn.xwiki.XWiki xwiki = context.getWiki(); + // Step 1: Copy the document and all its translations under a new name - context.getWiki().copyDocument(getFullName(), newDocumentName, false, context); + xwiki.copyDocument(getFullName(), newDocumentName, false, context); - // Step 2: For each backlink to rename, parse the backlink document and replace the links + // Step 2: For each child document, update parent. + if(childDocumentNames != null){ + String newParent = newDocName.getWiki() + ":" + newDocName.getSpace() + "." + newDocName.getPage(); + + for (String childDocumentName : childDocumentNames) { + XWikiDocument childDocument = xwiki.getDocument(childDocumentName, context); + + childDocument.setParent(newParent); + + xwiki.saveDocument(childDocument, + context.getMessageTool().get("core.comment.renameParent", Arrays.asList(new String[] {newDocumentName})), + true, context); + } + } + + // Step 3: For each backlink to rename, parse the backlink document and replace the links // with the new name. // Note: we ignore invalid links here. Invalid links should be shown to the user so // that they fix them but the rename feature ignores them. DocumentParser documentParser = new DocumentParser(); for (String backlinkDocumentName : backlinkDocumentNames) { - XWikiDocument backlinkDocument = context.getWiki().getDocument(backlinkDocumentName, context); + XWikiDocument backlinkDocument = xwiki.getDocument(backlinkDocumentName, context); if (backlinkDocument.is10Syntax()) { // Note: Here we cannot do a simple search/replace as there are several ways to point @@ -4089,17 +4129,18 @@ backlinkDocument.refactorDocumentLinks(oldDocName, newDocName, context); } - context.getWiki().saveDocument(backlinkDocument, + xwiki.saveDocument(backlinkDocument, context.getMessageTool().get("core.comment.renameLink", Arrays.asList(new String[] {newDocumentName})), true, context); } - // Step 3: Delete the old document - context.getWiki().deleteDocument(this, context); + // Step 4: Delete the old document + xwiki.deleteDocument(this, context); - // Step 4: The current document needs to point to the renamed document as otherwise it's + // Step 5: The current document needs to point to the renamed document as otherwise it's // pointing to an invalid XWikiDocument object as it's been deleted... - clone(context.getWiki().getDocument(newDocumentName, context)); + clone(xwiki.getDocument(newDocumentName, context)); + } private void refactorDocumentLinks(DocumentName oldDocumentName, DocumentName newDocumentName, XWikiContext context) Index: xwiki-core/src/main/java/com/xpn/xwiki/api/Document.java =================================================================== --- xwiki-core/src/main/java/com/xpn/xwiki/api/Document.java (revision 22772) +++ xwiki-core/src/main/java/com/xpn/xwiki/api/Document.java (working copy) @@ -1967,8 +1967,10 @@ } /** - * Rename the current document and all the backlinks leading to it. See - * {@link #renameDocument(String, java.util.List)} for more details. + * Rename the current document and all the backlinks leading to it. + * Will also change parent field in all documents which list the + * renamed document as their parent. See + * {@link #renameDocument(String, java.util.List, java.util.List)} for more details. * * @param newDocumentName the new document name. If the space is not specified then defaults to the current space. * @throws XWikiException in case of an error @@ -1978,7 +1980,7 @@ if (hasAccessLevel("delete") && this.context.getWiki().checkAccess("edit", this.context.getWiki().getDocument(newDocumentName, this.context), this.context)) { - this.doc.rename(newDocumentName, getXWikiContext()); + this.doc.rename(newDocumentName, getBacklinks(), getChildren(), getXWikiContext()); } } @@ -1992,6 +1994,26 @@ } /** + * Rename the current document and backlinks leading to it from specified documents. + * Will not change parent field in any documents which list the + * document we are renaming as their parent. See + * {@link #renameDocument(String, java.util.List, java.util.List)} for more details. + * + * @param newDocumentName the new document name. If the space is not specified then defaults to the current space. + * @param backlinkDocumentNames the list of documents to parse and for which links will be modified to point to the + * new renamed document. + * @throws XWikiException in case of an error + */ + public void rename(String newDocumentName, List backlinkDocumentNames) throws XWikiException + { + if (hasAccessLevel("delete") + && this.context.getWiki().checkAccess("edit", + this.context.getWiki().getDocument(newDocumentName, this.context), this.context)) { + this.doc.rename(newDocumentName, backlinkDocumentNames, null, getXWikiContext()); + } + } + + /** * Rename the current document and all the links pointing to it in the list of passed backlink documents. The * renaming algorithm takes into account the fact that there are several ways to write a link to a given page and * all those forms need to be renamed. For example the following links all point to the same page: @@ -2002,17 +2024,39 @@ *
  • [CurrentSpace.Page]
  • * *

    - * Note: links without a space are renamed with the space added. + * Note: links without a space are renamed with the space added and all documents given in childDocumentNames list + * have their parent field set to "currentwiki:CurrentSpace.Page". *

    * * @param newDocumentName the new document name. If the space is not specified then defaults to the current space. * @param backlinkDocumentNames the list of documents to parse and for which links will be modified to point to the * new renamed document. + * @param childDocumentNames the list of documents whose parent field will be set to the new document name. * @throws XWikiException in case of an error */ - public void rename(String newDocumentName, List backlinkDocumentNames) throws XWikiException + public void rename(String newDocumentName, List backlinkDocumentNames, List childDocumentNames) + throws XWikiException { - this.doc.rename(newDocumentName, backlinkDocumentNames, getXWikiContext()); + if (hasAccessLevel("delete") + && this.context.getWiki().checkAccess("edit", + this.context.getWiki().getDocument(newDocumentName, this.context), this.context)) { + + //Every page given in childDocumentNames has it's parent changed whether it needs it or not. + //Let's make sure the user has edit permission on any page given which is not actually a child. + //Otherwise it would be embarrassing if a user called: + //$doc.rename("mynewpage",$doc.getBacklinks(),$xwiki.searchDocuments("true")) + int counter = childDocumentNames.size(); + List actuallyChildren = getChildren(); + while(counter > 0){ + counter--; + if(!actuallyChildren.contains(childDocumentNames.get(counter)) + && !this.context.getWiki().checkAccess("edit", + this.context.getWiki().getDocument(childDocumentNames.get(counter), this.context), this.context) + ){return;} + } + + this.doc.rename(newDocumentName, backlinkDocumentNames, childDocumentNames, getXWikiContext()); + } } /** Index: xwiki-core/src/main/resources/ApplicationResources.properties =================================================================== --- xwiki-core/src/main/resources/ApplicationResources.properties (revision 22772) +++ xwiki-core/src/main/resources/ApplicationResources.properties (working copy) @@ -611,6 +611,7 @@ core.rename.newpage=New page core.rename.title.newName=New document name core.rename.title.updateDocs=Documents having backlinks to modify +core.rename.title.updateChildren=Documents listing this as their parent core.rename.submit=Rename core.rename.success=Successfully renamed {0} to {1} core.rename.emptyName=Please enter a valid page name! @@ -655,6 +656,7 @@ core.comment.deleteAttachmentComment=Deletion of attachment {0} core.comment.deleteImageComment=Deletion of image {0} core.comment.renameLink=Renamed links to {0} following the rename of that page +core.comment.renameParent=Changed parent to {0} following the rename of that page core.comment.createdTemplate=Created {0} Template core.minoredit=Is minor edit