From d2d9a57524b93fc571c2d796274e0530a2989165 Mon Sep 17 00:00:00 2001 From: Simon Urli Date: Tue, 10 Dec 2024 15:48:17 +0100 Subject: [PATCH] XWIKI-22571: Backlinks update changes an absolute reference to the moved page into one relative to the current wiki (#3654) * Use default serializer if the wiki is present in a link, not the compact serializer * Provide unit test and integration test to cover this * Fix DeletePageIT tests * simplify condition by using the relative resource reference resolver * fix tests --- .../flamingo/test/docker/DeletePageIT.java | 8 +- .../flamingo/test/docker/RenamePageIT.java | 20 +++ .../internal/ResourceReferenceRenamer.java | 30 +++- .../internal/DefaultReferenceUpdaterTest.java | 156 ++++++++++++++---- .../ResourceReferenceRenamerTest.java | 42 ++++- 5 files changed, 209 insertions(+), 47 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/DeletePageIT.java b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/DeletePageIT.java index ffd26b99768e..e736e4dbb25f 100644 --- a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/DeletePageIT.java +++ b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/DeletePageIT.java @@ -773,7 +773,7 @@ void deleteWithUpdateLinksAndAutoRedirect(TestUtils testUtils, TestReference ref // Verify that a redirect was added and the link was updated. viewPage = testUtils.gotoPage(reference); assertEquals("New target", this.viewPage.getDocumentTitle()); - assertEquals("[[Link>>doc:NewTarget.WebHome]]", + assertEquals("[[Link>>doc:xwiki:NewTarget.WebHome]]", testUtils.rest().get(backlinkDocumentReference).getContent()); } @@ -826,7 +826,7 @@ void deleteWithAffectChildrenAndNewTarget(TestUtils testUtils, TestReference par TestConfiguration testConfiguration) throws Exception { DocumentReference childReference = new DocumentReference("Child", parentReference.getLastSpaceReference()); - String childFullName = testUtils.serializeReference(childReference).split(":")[1]; + String childFullName = testUtils.serializeLocalReference(childReference); DocumentReference backlinkDocReference = new DocumentReference("xwiki", "Backlink", "WebHome"); DocumentReference newTargetReference = new DocumentReference("xwiki", "NewTarget", "WebHome"); @@ -836,7 +836,7 @@ void deleteWithAffectChildrenAndNewTarget(TestUtils testUtils, TestReference par // Create backlinks to the parent and the child page. String format = "[[Parent>>doc:%s]] [[Child>>doc:%s]]"; testUtils.createPage(backlinkDocReference, - String.format(format, testUtils.serializeReference(parentReference), childFullName), "Backlink document"); + String.format(format, testUtils.serializeLocalReference(parentReference), childFullName), "Backlink document"); // Wait for Solr indexing to complete as backlink information from Solr is needed new SolrTestUtils(testUtils, testConfiguration.getServletEngine()).waitEmptyQueue(); @@ -855,7 +855,7 @@ void deleteWithAffectChildrenAndNewTarget(TestUtils testUtils, TestReference par // Verify that there is no redirect on the child page and backlink was not altered. assertEquals(DELETE_SUCCESSFUL, deletingPage.getInfoMessage()); String newContent = - String.format(format, testUtils.serializeReference(newTargetReference).split(":")[1], childFullName); + String.format(format, testUtils.serializeLocalReference(newTargetReference), childFullName); assertEquals(newContent, testUtils.rest().get(backlinkDocReference).getContent()); parentPage = testUtils.gotoPage(parentReference); assertEquals("New target", parentPage.getDocumentTitle()); diff --git a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/RenamePageIT.java b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/RenamePageIT.java index ae59c7810ea4..3d6a669b6478 100644 --- a/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/RenamePageIT.java +++ b/xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/RenamePageIT.java @@ -723,4 +723,24 @@ void renameWithRelativeLinks(TestUtils testUtils, TestReference testReference, T //wikiEditPage = WikiEditPage.gotoPage(new DocumentReference("WebHome", newBobSpace)); //assertEquals(String.format("[[%s]]", serializedAlice2Reference), wikiEditPage.getContent()); } + + @Order(10) + @Test + void renameLinkContainingWiki(TestUtils testUtils, TestReference testReference, TestConfiguration testConfiguration) + throws Exception + { + DocumentReference documentReference = new DocumentReference("xwiki", "TestLinkWithWiki", "WebHome"); + testUtils.rest().delete(documentReference); + testUtils.rest().savePage(documentReference, "Some content", "TestLinkWithWiki"); + testUtils.rest().savePage(testReference, "[[MyPage>>xwiki:TestLinkWithWiki.WebHome]]", + "renameLinkContainingWiki"); + new SolrTestUtils(testUtils, testConfiguration.getServletEngine()).waitEmptyQueue(); + RenamePage renamePage = testUtils.gotoPage(documentReference).rename(); + renamePage.getDocumentPicker().setName("TestLinkWithWikiNew"); + CopyOrRenameOrDeleteStatusPage statusPage = + renamePage.clickRenameButton().waitUntilFinished(); + assertEquals("Done.", statusPage.getInfoMessage()); + WikiEditPage wikiEditPage = WikiEditPage.gotoPage(testReference); + assertEquals("[[MyPage>>xwiki:TestLinkWithWikiNew.WebHome]]", wikiEditPage.getContent()); + } } diff --git a/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/main/java/org/xwiki/refactoring/internal/ResourceReferenceRenamer.java b/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/main/java/org/xwiki/refactoring/internal/ResourceReferenceRenamer.java index a0729086e16a..8d672d573ef5 100644 --- a/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/main/java/org/xwiki/refactoring/internal/ResourceReferenceRenamer.java +++ b/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/main/java/org/xwiki/refactoring/internal/ResourceReferenceRenamer.java @@ -59,10 +59,17 @@ public class ResourceReferenceRenamer @Inject private EntityReferenceResolver entityReferenceResolver; + @Inject + @Named("relative") + private EntityReferenceResolver relativeEntityReferenceResolver; + @Inject @Named("compact") private EntityReferenceSerializer compactEntityReferenceSerializer; + @Inject + private EntityReferenceSerializer defaultEntityReferenceSerializer; + @Inject private DocumentReferenceResolver defaultReferenceDocumentReferenceResolver; @@ -152,8 +159,6 @@ private boolean updateAbsoluteResourceReference(ResourceReference resourceRefere DocumentReference absoluteResolvedDocumentReference = this.defaultReferenceDocumentReferenceResolver.resolve(absoluteResolvedEntityReference); - boolean isRelativePageReferenceOutsideOfParent = false; - // If the link targets the old (renamed) document reference and it's an absolute reference // (i.e. its resolution without any given parameter gives same result than its resolution with the // currentDocument) then we must update it @@ -193,9 +198,8 @@ private boolean updateAbsoluteResourceReference(ResourceReference resourceRefere newTargetReference = new AttachmentReference(linkEntityReference.getName(), newReference); } - String newReferenceString = - this.compactEntityReferenceSerializer.serialize(newTargetReference, currentDocumentReference); - + String newReferenceString = getNewTargetReference(resourceReference, newTargetReference, + currentDocumentReference); resourceReference.setReference(newReferenceString); resourceReference.setType(newResourceType); result = true; @@ -203,6 +207,19 @@ private boolean updateAbsoluteResourceReference(ResourceReference resourceRefere return result; } + private String getNewTargetReference(ResourceReference resourceReference, EntityReference newTargetReference, + EntityReference currentReference) + { + EntityReference entityReference = + this.relativeEntityReferenceResolver.resolve(resourceReference, null, (Object) null); + // If the reference contains the wiki name, then we should keep the absolute serialization. + if (entityReference.extractReference(EntityType.WIKI) != null) { + return this.defaultEntityReferenceSerializer.serialize(newTargetReference, currentReference); + } else { + return this.compactEntityReferenceSerializer.serialize(newTargetReference, currentReference); + } + } + private boolean isPageReferenceOutOfParent(ResourceReference resourceReference, DocumentReference linkTargetDocumentReference, Map updatedEntities) { @@ -266,8 +283,7 @@ private boolean updateRelativeResourceReference(Reso if (shouldBeUpdated) { // Serialize the old (original) link relative to the new document's location, in compact form. - String serializedLinkReference = - this.compactEntityReferenceSerializer.serialize(oldLinkReference, newReference); + String serializedLinkReference = getNewTargetReference(resourceReference, oldLinkReference, newReference); resourceReference.setReference(serializedLinkReference); result = true; } diff --git a/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/test/java/org/xwiki/refactoring/internal/DefaultReferenceUpdaterTest.java b/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/test/java/org/xwiki/refactoring/internal/DefaultReferenceUpdaterTest.java index 3c5fe356493f..e9e5efca5842 100644 --- a/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/test/java/org/xwiki/refactoring/internal/DefaultReferenceUpdaterTest.java +++ b/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/test/java/org/xwiki/refactoring/internal/DefaultReferenceUpdaterTest.java @@ -19,8 +19,6 @@ */ package org.xwiki.refactoring.internal; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -40,6 +38,7 @@ import org.xwiki.job.JobContext; import org.xwiki.job.Request; import org.xwiki.job.event.status.JobProgressManager; +import org.xwiki.model.EntityType; import org.xwiki.model.reference.AttachmentReference; import org.xwiki.model.reference.DocumentReference; import org.xwiki.model.reference.DocumentReferenceResolver; @@ -116,6 +115,9 @@ class DefaultReferenceUpdaterTest @Named("compact") private EntityReferenceSerializer compactEntityReferenceSerializer; + @MockComponent + private EntityReferenceSerializer defaultEntityReferenceSerializer; + @MockComponent private DocumentReferenceResolver defaultReferenceDocumentReferenceResolver; @@ -147,6 +149,10 @@ class DefaultReferenceUpdaterTest @MockComponent private JobContext jobContext; + @MockComponent + @Named("relative") + private EntityReferenceResolver relativeEntityReferenceResolver; + @Mock private Job job; @@ -220,7 +226,7 @@ private void setTextarea(XWikiDocument document, XDOM xdom) .thenReturn(new ObjectPropertyReference("area", new ObjectReference("areaobject", documentReference))); when(document.getXObjects()) - .thenReturn(Collections.singletonMap(documentReference, Collections.singletonList(baseObject))); + .thenReturn(Map.of(documentReference, List.of(baseObject))); when(this.contentParser.parse("areacontent", Syntax.XWIKI_2_1, documentReference)).thenReturn(xdom); } @@ -242,40 +248,58 @@ void updateRelativeLinks() throws Exception // Setup document content ResourceReference docLinkReference = new ResourceReference("C", ResourceType.DOCUMENT); - LinkBlock docLinkBlock = new LinkBlock(Collections.emptyList(), docLinkReference, false); + LinkBlock docLinkBlock = new LinkBlock(List.of(), docLinkReference, false); ResourceReference spaceLinkReference = new ResourceReference("Z", ResourceType.SPACE); - LinkBlock spaceLinkBlock = new LinkBlock(Collections.emptyList(), spaceLinkReference, false); + LinkBlock spaceLinkBlock = new LinkBlock(List.of(), spaceLinkReference, false); ResourceReference imageReference = new AttachmentResourceReference("attachment.txt"); ImageBlock imageBlock = new ImageBlock(imageReference, false); + ResourceReference absoluteDocLinkResourceReference = new ResourceReference("xwiki:C.WebHome", + ResourceType.DOCUMENT); + LinkBlock absoluteDocLinkBlock = + new LinkBlock(List.of(), absoluteDocLinkResourceReference, false); when(newDocument.getXDOM()) - .thenReturn(new XDOM(Arrays.asList(docLinkBlock, spaceLinkBlock, imageBlock))); + .thenReturn(new XDOM(List.of(docLinkBlock, spaceLinkBlock, imageBlock, absoluteDocLinkBlock))); // Setup object content ResourceReference xobjectDocLinkReference = new ResourceReference("C", ResourceType.DOCUMENT); - LinkBlock xobjectDocLinkBlock = new LinkBlock(Collections.emptyList(), xobjectDocLinkReference, false); + LinkBlock xobjectDocLinkBlock = new LinkBlock(List.of(), xobjectDocLinkReference, false); ResourceReference xobjectSpaceLinkReference = new ResourceReference("Z", ResourceType.SPACE); LinkBlock xobjectSpaceLinkBlock = - new LinkBlock(Collections.emptyList(), xobjectSpaceLinkReference, false); + new LinkBlock(List.of(), xobjectSpaceLinkReference, false); ResourceReference xobjectImageReference = new AttachmentResourceReference("attachment.txt"); ImageBlock xobjectImageBlock = new ImageBlock(xobjectImageReference, false); setTextarea(newDocument, - new XDOM(Arrays.asList(xobjectDocLinkBlock, xobjectSpaceLinkBlock, xobjectImageBlock))); + new XDOM(List.of(xobjectDocLinkBlock, xobjectSpaceLinkBlock, xobjectImageBlock))); DocumentReference originalDocLinkReference = new DocumentReference("WebHome", new SpaceReference("C", oldReference.getLastSpaceReference())); DocumentReference absoluteDocLinkReference = new DocumentReference("WebHome", new SpaceReference("wiki", "C")); + EntityReference relativeDocLinkReference = new EntityReference("WebHome", EntityType.DOCUMENT, + new EntityReference("C", EntityType.SPACE)); when(this.resourceReferenceResolver.resolve(docLinkReference, null)) .thenReturn(absoluteDocLinkReference); + when(this.relativeEntityReferenceResolver.resolve(docLinkReference, null, null)) + .thenReturn(relativeDocLinkReference); + when(this.resourceReferenceResolver.resolve(absoluteDocLinkResourceReference, null)) + .thenReturn(absoluteDocLinkReference); + when(this.relativeEntityReferenceResolver.resolve(absoluteDocLinkResourceReference, null, null)) + .thenReturn(absoluteDocLinkReference); when(this.resourceReferenceResolver.resolve(docLinkReference, null, oldReference)) .thenReturn(originalDocLinkReference); + when(this.resourceReferenceResolver.resolve(absoluteDocLinkResourceReference, null, oldReference)) + .thenReturn(absoluteDocLinkReference); when(this.resourceReferenceResolver.resolve(xobjectDocLinkReference, null)) .thenReturn(absoluteDocLinkReference); + when(this.relativeEntityReferenceResolver.resolve(xobjectDocLinkReference, null, null)) + .thenReturn(relativeDocLinkReference); when(this.resourceReferenceResolver.resolve(xobjectDocLinkReference, null, oldReference)) .thenReturn(originalDocLinkReference); when(this.resourceReferenceResolver.resolve(imageReference, null)) .thenReturn(absoluteTargetAttachment); when(this.resourceReferenceResolver.resolve(imageReference, null, oldReference)) .thenReturn(oldImageTargetAttachment); + when(this.relativeEntityReferenceResolver.resolve(imageReference, null, null)) + .thenReturn(relativeDocLinkReference); DocumentReference newDocLinkReference = new DocumentReference("WebHome", new SpaceReference("C", newReference.getLastSpaceReference())); when(this.resourceReferenceResolver.resolve(docLinkReference, null, newReference)) @@ -284,10 +308,15 @@ void updateRelativeLinks() throws Exception .thenReturn(newDocLinkReference); when(this.resourceReferenceResolver.resolve(imageReference, null, newReference)) .thenReturn(newImageTargetAttachment); + when(this.resourceReferenceResolver.resolve(absoluteDocLinkResourceReference, null, newReference)) + .thenReturn(new DocumentReference("WebHome", new SpaceReference("wiki", "E"))); SpaceReference originalSpaceReference = new SpaceReference("wiki", "Z"); + EntityReference relativeSpaceReference = new EntityReference("Z", EntityType.SPACE); when(this.resourceReferenceResolver.resolve(spaceLinkReference, null)) .thenReturn(originalSpaceReference); + when(this.relativeEntityReferenceResolver.resolve(spaceLinkReference, null, null)) + .thenReturn(relativeSpaceReference); when(this.resourceReferenceResolver.resolve(spaceLinkReference, null, oldReference)) .thenReturn(originalSpaceReference); when(this.resourceReferenceResolver.resolve(xobjectSpaceLinkReference, null)) @@ -300,12 +329,16 @@ void updateRelativeLinks() throws Exception .thenReturn(originalSpaceReference); when(this.compactEntityReferenceSerializer.serialize(originalDocLinkReference, newReference)).thenReturn("A.C"); + when(this.defaultEntityReferenceSerializer.serialize(absoluteDocLinkReference, newReference)) + .thenReturn("wiki:C.WebHome"); updater.update(newReference, oldReference, newReference); // Document link block is updated. assertEquals("A.C", docLinkBlock.getReference().getReference()); assertEquals(ResourceType.DOCUMENT, docLinkBlock.getReference().getType()); + assertEquals("wiki:C.WebHome", absoluteDocLinkBlock.getReference().getReference()); + assertEquals(ResourceType.DOCUMENT, absoluteDocLinkBlock.getReference().getType()); // Space link block stays the same, since they were on the same wiki. assertEquals("Z", spaceLinkBlock.getReference().getReference()); assertEquals(ResourceType.SPACE, spaceLinkBlock.getReference().getType()); @@ -339,22 +372,27 @@ void updateRelativeLinksAcrossWikis() throws Exception when(newDocument.getXDOM()).thenReturn(xdom); ResourceReference docLinkReference = new ResourceReference("C", ResourceType.DOCUMENT); - LinkBlock docLinkBlock = new LinkBlock(Collections.emptyList(), docLinkReference, false); + LinkBlock docLinkBlock = new LinkBlock(List.of(), docLinkReference, false); ResourceReference spaceLinkReference = new ResourceReference("Z", ResourceType.SPACE); - LinkBlock spaceLinkBlock = new LinkBlock(Collections.emptyList(), spaceLinkReference, false); + LinkBlock spaceLinkBlock = new LinkBlock(List.of(), spaceLinkReference, false); when(xdom.getBlocks(any(), eq(Block.Axes.DESCENDANT))) - .thenReturn(Arrays.asList(docLinkBlock, spaceLinkBlock)); + .thenReturn(List.of(docLinkBlock, spaceLinkBlock)); DocumentReference originalDocLinkReference = new DocumentReference("C", oldReference.getLastSpaceReference()); DocumentReference absoluteDocLinkReference = new DocumentReference("C", new SpaceReference("xwiki", "Main")); + EntityReference relativeDocLinkReference = new EntityReference("C", EntityType.DOCUMENT, + new EntityReference("B", EntityType.SPACE)); + EntityReference relativeSpaceLinkReference = new EntityReference("Z", EntityType.SPACE); when(this.resourceReferenceResolver.resolve(docLinkReference, null)).thenReturn(absoluteDocLinkReference); when(this.resourceReferenceResolver.resolve(docLinkReference, null, oldReference)) .thenReturn(originalDocLinkReference); DocumentReference newDocLinkReference = new DocumentReference("C", newReference.getLastSpaceReference()); when(this.resourceReferenceResolver.resolve(docLinkReference, null, newReference)) .thenReturn(newDocLinkReference); + when(this.relativeEntityReferenceResolver.resolve(docLinkReference, null, null)) + .thenReturn(relativeDocLinkReference); SpaceReference originalSpaceReference = new SpaceReference("wiki1", "Z"); SpaceReference absoluteSpaceReference = new SpaceReference("xwiki", "Z"); @@ -364,6 +402,8 @@ void updateRelativeLinksAcrossWikis() throws Exception SpaceReference newSpaceReference = new SpaceReference("wiki2", "Z"); when(this.resourceReferenceResolver.resolve(spaceLinkReference, null, newReference)) .thenReturn(newSpaceReference); + when(this.relativeEntityReferenceResolver.resolve(spaceLinkReference, null, null)) + .thenReturn(relativeSpaceLinkReference); when(this.compactEntityReferenceSerializer.serialize(originalDocLinkReference, newReference)) .thenReturn("wiki1:A.C"); @@ -396,29 +436,49 @@ void update() throws Exception // Setup document content ResourceReference linkReference = new ResourceReference("A.B", ResourceType.DOCUMENT); - LinkBlock linkBlock = new LinkBlock(Collections.emptyList(), linkReference, false); - XDOM xdom = new XDOM(Collections.singletonList(linkBlock)); + LinkBlock linkBlock = new LinkBlock(List.of(), linkReference, false); + ResourceReference absoluteLinkReference = new ResourceReference("xwiki:A.B.WebHome", ResourceType.DOCUMENT); + LinkBlock absoluteLinkBlock = new LinkBlock(List.of(), absoluteLinkReference, false); + XDOM xdom = new XDOM(List.of(linkBlock, absoluteLinkBlock)); when(document.getXDOM()).thenReturn(xdom); // Setup object content ResourceReference xobjectLinkReference = new ResourceReference("A.B", ResourceType.DOCUMENT); - LinkBlock xobjectLinkBlock = new LinkBlock(Collections.emptyList(), xobjectLinkReference, false); - XDOM xobjectXDOM = new XDOM(Collections.singletonList(xobjectLinkBlock)); + LinkBlock xobjectLinkBlock = new LinkBlock(List.of(), xobjectLinkReference, false); + XDOM xobjectXDOM = new XDOM(List.of(xobjectLinkBlock)); setTextarea(document, xobjectXDOM); + EntityReference relativeLinkReference = new EntityReference("B", EntityType.DOCUMENT, + new EntityReference("A", EntityType.SPACE)); + EntityReference relativeAbsoluteLinkReference = new EntityReference("WebHome", EntityType.DOCUMENT, + new EntityReference("B", EntityType.SPACE, new EntityReference("B", EntityType.SPACE, + new EntityReference("xwiki", EntityType.WIKI)))); + when(this.resourceReferenceResolver.resolve(linkReference, null)).thenReturn(oldLinkTarget); when(this.resourceReferenceResolver.resolve(linkReference, null, documentReference)).thenReturn(oldLinkTarget); + when(this.resourceReferenceResolver.resolve(absoluteLinkReference, null)).thenReturn(oldLinkTarget); + when(this.resourceReferenceResolver.resolve(absoluteLinkReference, null, documentReference)) + .thenReturn(oldLinkTarget); when(this.resourceReferenceResolver.resolve(xobjectLinkReference, null)) .thenReturn(oldLinkTarget); when(this.resourceReferenceResolver.resolve(xobjectLinkReference, null, documentReference)) .thenReturn(oldLinkTarget); when(this.defaultReferenceDocumentReferenceResolver.resolve(oldLinkTarget)).thenReturn(oldLinkTarget); + when(this.relativeEntityReferenceResolver.resolve(xobjectLinkReference,null, null)) + .thenReturn(relativeLinkReference); + when(this.relativeEntityReferenceResolver.resolve(linkReference, null, null)) + .thenReturn(relativeLinkReference); + when(this.relativeEntityReferenceResolver.resolve(absoluteLinkReference, null, null)) + .thenReturn(relativeAbsoluteLinkReference); when(this.compactEntityReferenceSerializer.serialize(newLinkTarget, documentReference)).thenReturn("X.Y"); + when(this.defaultEntityReferenceSerializer.serialize(newLinkTarget, documentReference)) + .thenReturn("xwiki:X.Y.WebHome"); updater.update(documentReference, oldLinkTarget, newLinkTarget); assertEquals("X.Y", linkBlock.getReference().getReference()); + assertEquals("xwiki:X.Y.WebHome", absoluteLinkBlock.getReference().getReference()); assertEquals("X.Y", xobjectLinkBlock.getReference().getReference()); assertEquals(ResourceType.DOCUMENT, linkBlock.getReference().getType()); verifyDocumentSave(document, "Renamed back-links.", false, false); @@ -444,13 +504,17 @@ void renameImage() throws Exception ResourceReference imageReference = new AttachmentResourceReference("A.B@attachment.txt"); ImageBlock imageBlock = new ImageBlock(imageReference, false); - when(xdom.getBlocks(any(), eq(Block.Axes.DESCENDANT))).thenReturn(Arrays.asList(imageBlock)); + when(xdom.getBlocks(any(), eq(Block.Axes.DESCENDANT))).thenReturn(List.of(imageBlock)); + + EntityReference relativeReference = new EntityReference("attachment.txt", EntityType.ATTACHMENT, + new EntityReference("B", EntityType.DOCUMENT, new EntityReference("A", EntityType.SPACE))); when(this.resourceReferenceResolver.resolve(imageReference, null)).thenReturn(oldImageTargetAttachment); when(this.resourceReferenceResolver.resolve(imageReference, null, documentReference)) .thenReturn(oldImageTargetAttachment); when(this.defaultReferenceDocumentReferenceResolver.resolve(oldImageTargetAttachment)) .thenReturn(oldImageTarget); + when(this.relativeEntityReferenceResolver.resolve(imageReference, null, null)).thenReturn(relativeReference); when(this.compactEntityReferenceSerializer.serialize(newImageTargetAttachment, documentReference)) .thenReturn("X.Y@attachment.txt"); @@ -463,7 +527,7 @@ void renameImage() throws Exception } @Test - public void renameAttachment() throws Exception + void renameAttachment() throws Exception { DocumentReference documentReference = new DocumentReference("wiki", "Space", "Page"); XWikiDocument document = mock(XWikiDocument.class); @@ -481,14 +545,18 @@ public void renameAttachment() throws Exception when(document.getXDOM()).thenReturn(xdom); ResourceReference linkReference = new AttachmentResourceReference("A.B@attachment.txt"); - LinkBlock linkBlock = new LinkBlock(Collections.emptyList(), linkReference, false); - when(xdom.getBlocks(any(), eq(Block.Axes.DESCENDANT))).thenReturn(Arrays.asList(linkBlock)); + LinkBlock linkBlock = new LinkBlock(List.of(), linkReference, false); + when(xdom.getBlocks(any(), eq(Block.Axes.DESCENDANT))).thenReturn(List.of(linkBlock)); + + EntityReference relativeReference = new EntityReference("attachment.txt", EntityType.ATTACHMENT, + new EntityReference("B", EntityType.DOCUMENT, new EntityReference("A", EntityType.SPACE))); when(this.resourceReferenceResolver.resolve(linkReference, null)) .thenReturn(oldLinkTargetAttachment); when(this.resourceReferenceResolver.resolve(linkReference, null, documentReference)) .thenReturn(oldLinkTargetAttachment); when(this.defaultReferenceDocumentReferenceResolver.resolve(oldLinkTargetAttachment)).thenReturn(oldLinkTarget); + when(this.relativeEntityReferenceResolver.resolve(linkReference, null, null)).thenReturn(relativeReference); when(this.compactEntityReferenceSerializer.serialize(newLinkTargetAttachment, documentReference)) .thenReturn("X.Y@attachment.txt"); @@ -517,13 +585,16 @@ void renameNonTerminalDocumentLinks() throws Exception when(document.getXDOM()).thenReturn(xdom); ResourceReference docLinkReference = new ResourceReference("A.WebHome", ResourceType.DOCUMENT); - LinkBlock documentLinkBlock = new LinkBlock(Collections.emptyList(), docLinkReference, false); + LinkBlock documentLinkBlock = new LinkBlock(List.of(), docLinkReference, false); + EntityReference relativeReference = new EntityReference("WebHome", EntityType.DOCUMENT, + new EntityReference("A", EntityType.SPACE)); ResourceReference spaceLinkReference = new ResourceReference("A", ResourceType.SPACE); - LinkBlock spaceLinkBlock = new LinkBlock(Collections.emptyList(), spaceLinkReference, false); + LinkBlock spaceLinkBlock = new LinkBlock(List.of(), spaceLinkReference, false); + EntityReference relativeSpaceReference = new EntityReference("A", EntityType.SPACE); when(xdom.getBlocks(any(), eq(Block.Axes.DESCENDANT))) - .thenReturn(Arrays.asList(documentLinkBlock, spaceLinkBlock)); + .thenReturn(List.of(documentLinkBlock, spaceLinkBlock)); // Doc link when(this.resourceReferenceResolver.resolve(docLinkReference, null)) @@ -532,6 +603,7 @@ void renameNonTerminalDocumentLinks() throws Exception .thenReturn(oldLinkTarget); when(this.defaultReferenceDocumentReferenceResolver.resolve(oldLinkTarget)).thenReturn(oldLinkTarget); when(this.compactEntityReferenceSerializer.serialize(newLinkTarget, documentReference)).thenReturn("X.WebHome"); + when(this.relativeEntityReferenceResolver.resolve(docLinkReference, null, null)).thenReturn(relativeReference); // Space link SpaceReference spaceReference = oldLinkTarget.getLastSpaceReference(); @@ -542,6 +614,8 @@ void renameNonTerminalDocumentLinks() throws Exception when(this.defaultReferenceDocumentReferenceResolver.resolve(spaceReference)).thenReturn(oldLinkTarget); when(this.compactEntityReferenceSerializer.serialize(newLinkTarget.getLastSpaceReference(), documentReference)) .thenReturn("X"); + when(this.relativeEntityReferenceResolver.resolve(spaceLinkReference, null, null)) + .thenReturn(relativeSpaceReference); updater.update(documentReference, oldLinkTarget, newLinkTarget); @@ -569,13 +643,18 @@ void renameNonTerminalToTerminalDocumentLinks() throws Exception when(document.getXDOM()).thenReturn(xdom); ResourceReference docLinkReference = new ResourceReference("A.WebHome", ResourceType.DOCUMENT); - LinkBlock documentLinkBlock = new LinkBlock(Collections.emptyList(), docLinkReference, false); + LinkBlock documentLinkBlock = new LinkBlock(List.of(), docLinkReference, false); + + EntityReference relativeReference = new EntityReference("WebHome", EntityType.DOCUMENT, + new EntityReference("A", EntityType.SPACE)); ResourceReference spaceLinkReference = new ResourceReference("A", ResourceType.SPACE); - LinkBlock spaceLinkBlock = new LinkBlock(Collections.emptyList(), spaceLinkReference, false); + LinkBlock spaceLinkBlock = new LinkBlock(List.of(), spaceLinkReference, false); + + EntityReference relativeSpaceReference = new EntityReference("A", EntityType.SPACE); when(xdom.getBlocks(any(), eq(Block.Axes.DESCENDANT))) - .thenReturn(Arrays.asList(documentLinkBlock, spaceLinkBlock)); + .thenReturn(List.of(documentLinkBlock, spaceLinkBlock)); // Doc link when(this.resourceReferenceResolver.resolve(docLinkReference, null)) @@ -584,6 +663,7 @@ void renameNonTerminalToTerminalDocumentLinks() throws Exception .thenReturn(oldLinkTarget); when(this.defaultReferenceDocumentReferenceResolver.resolve(oldLinkTarget)).thenReturn(oldLinkTarget); when(this.compactEntityReferenceSerializer.serialize(newLinkTarget, documentReference)).thenReturn("X.Y"); + when(this.relativeEntityReferenceResolver.resolve(docLinkReference, null, null)).thenReturn(relativeReference); // Space link SpaceReference spaceReference = oldLinkTarget.getLastSpaceReference(); @@ -594,6 +674,8 @@ void renameNonTerminalToTerminalDocumentLinks() throws Exception when(this.defaultReferenceDocumentReferenceResolver.resolve(spaceReference)).thenReturn(oldLinkTarget); when(this.compactEntityReferenceSerializer.serialize(newLinkTarget.getLastSpaceReference(), documentReference)) .thenReturn("X"); + when(this.relativeEntityReferenceResolver.resolve(spaceLinkReference, null, null)) + .thenReturn(relativeSpaceReference); updater.update(documentReference, oldLinkTarget, newLinkTarget); @@ -638,7 +720,7 @@ void updateFromMacros(MockitoComponentManager componentManager) throws Exception displayMacroBlock.setParent(xdom); when(xdom.getBlocks(any(), eq(Block.Axes.DESCENDANT))) - .thenReturn(Arrays.asList(includeMacroBlock1, includeMacroBlock2, displayMacroBlock)); + .thenReturn(List.of(includeMacroBlock1, includeMacroBlock2, displayMacroBlock)); ResourceReference macroResourceReference = new ResourceReference("A.B", ResourceType.DOCUMENT); @@ -680,7 +762,7 @@ void updateAttachments() throws Exception DocumentReference targetDocument = new DocumentReference("wiki", "Space", "Target"); AttachmentReference newLinkTarget = new AttachmentReference("newname.txt", targetDocument); ResourceReference resourceReference = new ResourceReference("oldname.txt", ResourceType.ATTACHMENT); - LinkBlock documentLinkBlock = new LinkBlock(Collections.emptyList(), resourceReference, false); + LinkBlock documentLinkBlock = new LinkBlock(List.of(), resourceReference, false); XWikiDocument document = mock(XWikiDocument.class); XDOM xdom = mock(XDOM.class); @@ -734,10 +816,12 @@ void updateFromLinksAndMacros(MockitoComponentManager componentManager) throws E MacroBlock includeMacroBlock = new MacroBlock("include", includeParameters, false); ResourceReference resourceReference = new ResourceReference("A.B", ResourceType.DOCUMENT); - LinkBlock documentLinkBlock = new LinkBlock(Collections.emptyList(), resourceReference, false); + LinkBlock documentLinkBlock = new LinkBlock(List.of(), resourceReference, false); + EntityReference relativeReference = new EntityReference("B", EntityType.DOCUMENT, + new EntityReference("A", EntityType.SPACE)); when(xdom.getBlocks(any(), eq(Block.Axes.DESCENDANT))) - .thenReturn(Arrays.asList(includeMacroBlock, documentLinkBlock)); + .thenReturn(List.of(includeMacroBlock, documentLinkBlock)); when(this.resourceReferenceResolver.resolve(resourceReference, null)) .thenReturn(oldLinkTarget); @@ -745,6 +829,7 @@ void updateFromLinksAndMacros(MockitoComponentManager componentManager) throws E .thenReturn(oldLinkTarget); when(this.defaultReferenceDocumentReferenceResolver.resolve(oldLinkTarget)).thenReturn(oldLinkTarget); when(this.compactEntityReferenceSerializer.serialize(newLinkTarget, documentReference)).thenReturn("X.Y"); + when(this.relativeEntityReferenceResolver.resolve(resourceReference, null, null)).thenReturn(relativeReference); MacroRefactoring includeMacroRefactoring = componentManager.registerMockComponent(MacroRefactoring.class, "include"); @@ -784,7 +869,7 @@ void updateAndTranslations() throws Exception when(this.xcontext.getWiki().getDocument(baseDocumentReference, this.xcontext)).thenReturn(baseDocument); when(baseDocument.getDocumentReference()).thenReturn(baseDocumentReference); - when(baseDocument.getTranslationLocales(xcontext)).thenReturn(Arrays.asList(Locale.FRENCH, Locale.ENGLISH)); + when(baseDocument.getTranslationLocales(xcontext)).thenReturn(List.of(Locale.FRENCH, Locale.ENGLISH)); DocumentReference frenchDocumentReference = new DocumentReference("wiki", "Space", "Page", Locale.FRENCH); XWikiDocument frenchDocument = mock(XWikiDocument.class); when(baseDocument.getTranslatedDocument(Locale.FRENCH, xcontext)).thenReturn(frenchDocument); @@ -799,7 +884,7 @@ void updateAndTranslations() throws Exception DocumentReference oldLinkTarget = new DocumentReference("wiki", "A", "B"); DocumentReference newLinkTarget = new DocumentReference("wiki", "X", "Y"); - List documentsToUpdate = Arrays.asList(baseDocument, frenchDocument, englishDocument); + List documentsToUpdate = List.of(baseDocument, frenchDocument, englishDocument); for (XWikiDocument xWikiDocument : documentsToUpdate) { DocumentReference documentReference = xWikiDocument.getDocumentReference(); @@ -808,7 +893,9 @@ void updateAndTranslations() throws Exception when(xWikiDocument.getXDOM()).thenReturn(xdom); ResourceReference linkReference = new ResourceReference("A.B", ResourceType.DOCUMENT); - LinkBlock linkBlock = new LinkBlock(Collections.emptyList(), linkReference, false); + EntityReference relativeReference = new EntityReference("B", EntityType.DOCUMENT, + new EntityReference("A", EntityType.SPACE)); + LinkBlock linkBlock = new LinkBlock(List.of(), linkReference, false); when(xdom.getBlocks(any(), eq(Block.Axes.DESCENDANT))).thenReturn(List.of(linkBlock)); when(this.resourceReferenceResolver.resolve(linkReference, null)) @@ -816,8 +903,9 @@ void updateAndTranslations() throws Exception when(this.resourceReferenceResolver.resolve(linkReference, null, documentReference)) .thenReturn(oldLinkTarget); when(this.defaultReferenceDocumentReferenceResolver.resolve(oldLinkTarget)).thenReturn(oldLinkTarget); - when(this.compactEntityReferenceSerializer.serialize(newLinkTarget, documentReference)).thenReturn("X.Y"); + when(this.relativeEntityReferenceResolver.resolve(linkReference, null, null)) + .thenReturn(relativeReference); } updater.update(baseDocumentReference, oldLinkTarget, newLinkTarget); diff --git a/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/test/java/org/xwiki/refactoring/internal/ResourceReferenceRenamerTest.java b/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/test/java/org/xwiki/refactoring/internal/ResourceReferenceRenamerTest.java index 63cd5422cc40..bc3147a3ec4c 100644 --- a/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/test/java/org/xwiki/refactoring/internal/ResourceReferenceRenamerTest.java +++ b/xwiki-platform-core/xwiki-platform-refactoring/xwiki-platform-refactoring-default/src/test/java/org/xwiki/refactoring/internal/ResourceReferenceRenamerTest.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.xwiki.model.EntityType; import org.xwiki.model.reference.AttachmentReference; import org.xwiki.model.reference.DocumentReference; import org.xwiki.model.reference.DocumentReferenceResolver; @@ -71,12 +72,19 @@ class ResourceReferenceRenamerTest @Named("compact") private EntityReferenceSerializer compactEntityReferenceSerializer; + @MockComponent + private EntityReferenceSerializer defaultEntityReferenceSerializer; + @MockComponent private DocumentReferenceResolver defaultReferenceDocumentReferenceResolver; @MockComponent private PageReferenceResolver defaultReferencePageReferenceResolver; + @MockComponent + @Named("relative") + private EntityReferenceResolver relativeEntityReferenceResolver; + @MockComponent private Provider contextProvider; @@ -92,16 +100,46 @@ void setup() throws XWikiException } @Test - void updateResourceReferenceRelative() + void updateResourceReferenceRelativeOtherWiki() + { + DocumentResourceReference resourceReference = new DocumentResourceReference("Main.WebHome"); + AttachmentReference oldReference = + new AttachmentReference("file.txt", new DocumentReference("wiki", "space", "page")); + + EntityReference relativeReference = new EntityReference("file.txt", EntityType.ATTACHMENT, + new EntityReference("page", EntityType.DOCUMENT, new EntityReference("space", EntityType.SPACE, + new EntityReference("wiki", EntityType.WIKI)))); + AttachmentReference newReference = + new AttachmentReference("file2.txt", new DocumentReference("wiki", "space", "page")); + when(this.entityReferenceResolver.resolve(resourceReference, null)).thenReturn(oldReference); + when(this.entityReferenceResolver.resolve(resourceReference, null, newReference)).thenReturn(newReference); + when(this.entityReferenceResolver.resolve(resourceReference, null, oldReference)).thenReturn(oldReference); + when(this.relativeEntityReferenceResolver.resolve(resourceReference, null, null)).thenReturn(relativeReference); + when(this.compactEntityReferenceSerializer.serialize(oldReference, newReference)).thenReturn("file2.txt"); + + assertTrue(this.renamer.updateResourceReference(resourceReference, + oldReference, + newReference, + new DocumentReference("xwiki", "Space", "Page"), true, Map.of())); + + verify(this.defaultEntityReferenceSerializer).serialize(oldReference, newReference); + } + + @Test + void updateResourceReferenceRelativeSameWiki() { - DocumentResourceReference resourceReference = new DocumentResourceReference("xwiki:Main.WebHome"); + DocumentResourceReference resourceReference = new DocumentResourceReference("Main.WebHome"); AttachmentReference oldReference = new AttachmentReference("file.txt", new DocumentReference("wiki", "space", "page")); + + EntityReference relativeReference = new EntityReference("file.txt", EntityType.ATTACHMENT, + new EntityReference("page", EntityType.DOCUMENT, new EntityReference("space", EntityType.SPACE))); AttachmentReference newReference = new AttachmentReference("file2.txt", new DocumentReference("wiki", "space", "page")); when(this.entityReferenceResolver.resolve(resourceReference, null)).thenReturn(oldReference); when(this.entityReferenceResolver.resolve(resourceReference, null, newReference)).thenReturn(newReference); when(this.entityReferenceResolver.resolve(resourceReference, null, oldReference)).thenReturn(oldReference); + when(this.relativeEntityReferenceResolver.resolve(resourceReference, null, null)).thenReturn(relativeReference); when(this.compactEntityReferenceSerializer.serialize(oldReference, newReference)).thenReturn("file2.txt"); assertTrue(this.renamer.updateResourceReference(resourceReference,