From e5e3872becec4b06c43513b5624c2528bc36157f Mon Sep 17 00:00:00 2001 From: Vincent Massol Date: Fri, 9 Feb 2024 15:33:35 +0100 Subject: [PATCH 1/3] [Misc] Fix missing extension category metadata --- .../xwiki-platform-icon/xwiki-platform-icon-fontawesome/pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xwiki-platform-core/xwiki-platform-icon/xwiki-platform-icon-fontawesome/pom.xml b/xwiki-platform-core/xwiki-platform-icon/xwiki-platform-icon-fontawesome/pom.xml index aa1d8a801278..626f9ba71a08 100644 --- a/xwiki-platform-core/xwiki-platform-icon/xwiki-platform-icon-fontawesome/pom.xml +++ b/xwiki-platform-core/xwiki-platform-icon/xwiki-platform-icon-fontawesome/pom.xml @@ -34,6 +34,8 @@ Font Awesome Icon Theme + + icontheme From 78c97071d2f41809c3a2090d658e9fa9fac63530 Mon Sep 17 00:00:00 2001 From: Vincent Massol Date: Fri, 9 Feb 2024 16:15:46 +0100 Subject: [PATCH 2/3] [Misc] Move 2 tests to JUnit5 --- .../PathWikiReferenceExtractorTest.java | 69 ++++++++++--------- ...dedURLResourceReferenceSerializerTest.java | 51 +++++++------- 2 files changed, 62 insertions(+), 58 deletions(-) diff --git a/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/PathWikiReferenceExtractorTest.java b/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/PathWikiReferenceExtractorTest.java index f35d9fd11d40..a530f5e9ba7c 100644 --- a/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/PathWikiReferenceExtractorTest.java +++ b/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/PathWikiReferenceExtractorTest.java @@ -21,18 +21,19 @@ import java.net.URL; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.xwiki.context.Execution; import org.xwiki.context.ExecutionContext; import org.xwiki.model.reference.WikiReference; -import org.xwiki.test.mockito.MockitoComponentMockingRule; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; import org.xwiki.url.ExtendedURL; import org.xwiki.wiki.descriptor.WikiDescriptor; import org.xwiki.wiki.descriptor.WikiDescriptorManager; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; /** @@ -41,78 +42,81 @@ * @version $Id$ * @since 6.3M1 */ -public class PathWikiReferenceExtractorTest +@ComponentTest +class PathWikiReferenceExtractorTest { - @Rule - public MockitoComponentMockingRule mocker = - new MockitoComponentMockingRule<>(PathWikiReferenceExtractor.class); + @InjectMockComponents + private PathWikiReferenceExtractor extractor; + @MockComponent private WikiDescriptorManager wikiDescriptorManager; - @Before - public void setUp() throws Exception + @MockComponent + private Execution execution; + + @MockComponent + private StandardURLConfiguration urlConfiguration; + + @BeforeEach + void setUp() throws Exception { - this.wikiDescriptorManager = mocker.getInstance(WikiDescriptorManager.class); - when(wikiDescriptorManager.getMainWikiId()).thenReturn("xwiki"); + when(this.wikiDescriptorManager.getMainWikiId()).thenReturn("xwiki"); } @Test - public void extractWhenWikiDescriptor() throws Exception + void extractWhenWikiDescriptor() throws Exception { setUpConfiguration(WikiNotFoundBehavior.REDIRECT_TO_MAIN_WIKI); - WikiDescriptorManager wikiDescriptorManager = mocker.getInstance(WikiDescriptorManager.class); - when(wikiDescriptorManager.getByAlias("someWiki")).thenReturn(new WikiDescriptor("wikiid", "someWiki")); + when(this.wikiDescriptorManager.getByAlias("someWiki")).thenReturn(new WikiDescriptor("wikiid", "someWiki")); testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "wikiid"); } @Test - public void extractWhenNoWikiDescriptor() throws Exception + void extractWhenNoWikiDescriptor() throws Exception { setUpConfiguration(WikiNotFoundBehavior.REDIRECT_TO_MAIN_WIKI); testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "xwiki"); } @Test - public void extractWhenWikiDescriptorButEmptyServerName() throws Exception + void extractWhenWikiDescriptorButEmptyServerName() throws Exception { setUpConfiguration(WikiNotFoundBehavior.REDIRECT_TO_MAIN_WIKI); - WikiDescriptorManager wikiDescriptorManager = mocker.getInstance(WikiDescriptorManager.class); - when(wikiDescriptorManager.getByAlias("someWiki")).thenReturn(new WikiDescriptor("", "someWiki")); + when(this.wikiDescriptorManager.getByAlias("someWiki")).thenReturn(new WikiDescriptor("", "someWiki")); testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "xwiki"); } @Test - public void extractWhenNoDescriptorMatchingAliasButDescriptorMatchingId() throws Exception + void extractWhenNoDescriptorMatchingAliasButDescriptorMatchingId() throws Exception { setUpConfiguration(WikiNotFoundBehavior.REDIRECT_TO_MAIN_WIKI); - WikiDescriptorManager wikiDescriptorManager = mocker.getInstance(WikiDescriptorManager.class); - when(wikiDescriptorManager.getByAlias("someWiki")).thenReturn(null); - when(wikiDescriptorManager.getById("someWiki")).thenReturn(new WikiDescriptor("dummy", "dummy")); + when(this.wikiDescriptorManager.getByAlias("someWiki")).thenReturn(null); + when(this.wikiDescriptorManager.getById("someWiki")).thenReturn(new WikiDescriptor("dummy", "dummy")); testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "somewiki"); } @Test - public void extractWhenNoWikiDescriptorButWithDomainBasedURL() throws Exception + void extractWhenNoWikiDescriptorButWithDomainBasedURL() throws Exception { setUpConfiguration(WikiNotFoundBehavior.REDIRECT_TO_MAIN_WIKI); testAndAssert("http://wiki.server.com/xwiki/bin/view/Main/WebHome", "xwiki"); } @Test - public void extractWhenNoWikiDescriptorAndDisplayErrorWhenWikiNotFound() throws Exception + void extractWhenNoWikiDescriptorAndDisplayErrorWhenWikiNotFound() throws Exception { setUpConfiguration(WikiNotFoundBehavior.DISPLAY_ERROR); testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "somewiki"); } @Test - public void extractWhenNoExecutionContext() throws Exception + void extractWhenNoExecutionContext() throws Exception { testAndAssert("http://localhost/xwiki/wiki/someWiki/view/Main/WebHome", "somewiki"); @@ -125,19 +129,16 @@ private void testAndAssert(String urlToTest, String expectedWikiId) throws Excep ExtendedURL url = new ExtendedURL(new URL(urlToTest), "xwiki"); // Remove the resource type (i.e. the first segment) since this is what is expected by the extractor url.getSegments().remove(0); - WikiReference wikiReference = this.mocker.getComponentUnderTest().extract(url); + WikiReference wikiReference = this.extractor.extract(url); assertEquals(new WikiReference(expectedWikiId), wikiReference); } - private void setUpConfiguration(WikiNotFoundBehavior wikiNotFoundBehavior) throws Exception + private void setUpConfiguration(WikiNotFoundBehavior wikiNotFoundBehavior) { // Simulate a configured Execution Context - Execution execution = mocker.getInstance(Execution.class); ExecutionContext executionContext = new ExecutionContext(); executionContext.setProperty("xwikicontext", true); - when(execution.getContext()).thenReturn(executionContext); - - StandardURLConfiguration urlConfiguration = mocker.getInstance(StandardURLConfiguration.class); - when(urlConfiguration.getWikiNotFoundBehavior()).thenReturn(wikiNotFoundBehavior); + when(this.execution.getContext()).thenReturn(executionContext); + when(this.urlConfiguration.getWikiNotFoundBehavior()).thenReturn(wikiNotFoundBehavior); } } diff --git a/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/StandardExtendedURLResourceReferenceSerializerTest.java b/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/StandardExtendedURLResourceReferenceSerializerTest.java index 45bc91da00b1..1f387fdc9e1e 100644 --- a/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/StandardExtendedURLResourceReferenceSerializerTest.java +++ b/xwiki-platform-core/xwiki-platform-url/xwiki-platform-url-schemes/xwiki-platform-url-scheme-standard/src/test/java/org/xwiki/url/internal/standard/StandardExtendedURLResourceReferenceSerializerTest.java @@ -19,8 +19,9 @@ */ package org.xwiki.url.internal.standard; -import org.junit.Rule; -import org.junit.Test; +import javax.inject.Named; + +import org.junit.jupiter.api.Test; import org.xwiki.component.manager.ComponentLookupException; import org.xwiki.component.manager.ComponentManager; import org.xwiki.component.util.DefaultParameterizedType; @@ -28,11 +29,13 @@ import org.xwiki.resource.ResourceReferenceSerializer; import org.xwiki.resource.ResourceType; import org.xwiki.resource.UnsupportedResourceReferenceException; -import org.xwiki.test.mockito.MockitoComponentMockingRule; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; import org.xwiki.url.ExtendedURL; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.*; /** @@ -41,11 +44,15 @@ * @version $Id$ * @since 6.1M2 */ -public class StandardExtendedURLResourceReferenceSerializerTest +@ComponentTest +class StandardExtendedURLResourceReferenceSerializerTest { - @Rule - public MockitoComponentMockingRule mocker = - new MockitoComponentMockingRule<>(StandardExtendedURLResourceReferenceSerializer.class); + @InjectMockComponents + private StandardExtendedURLResourceReferenceSerializer serializer; + + @MockComponent + @Named("context") + private ComponentManager componentManager; public class TestResourceReference extends AbstractResourceReference { @@ -56,41 +63,37 @@ public TestResourceReference() } @Test - public void serialize() throws Exception + void serialize() throws Exception { TestResourceReference resource = new TestResourceReference(); ResourceReferenceSerializer serializer = mock(ResourceReferenceSerializer.class); - ComponentManager componentManager = this.mocker.getInstance(ComponentManager.class, "context"); - when(componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, + when(this.componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, TestResourceReference.class, ExtendedURL.class), "standard")).thenReturn(serializer); - this.mocker.getComponentUnderTest().serialize(resource); + this.serializer.serialize(resource); // Verify the serializer is called and with the proper parameters verify(serializer).serialize(same(resource)); } @Test - public void serializeWhenNoMatchingSerializer() throws Exception + void serializeWhenNoMatchingSerializer() throws Exception { TestResourceReference resource = new TestResourceReference(); - ComponentManager componentManager = this.mocker.getInstance(ComponentManager.class, "context"); - when(componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, + when(this.componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, TestResourceReference.class, ExtendedURL.class), "standard")).thenThrow( new ComponentLookupException("error")); - when(componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, + when(this.componentManager.getInstance(new DefaultParameterizedType(null, ResourceReferenceSerializer.class, TestResourceReference.class, ExtendedURL.class))).thenThrow( new ComponentLookupException("error")); - try { - this.mocker.getComponentUnderTest().serialize(resource); - fail("Should have thrown an exception here"); - } catch (UnsupportedResourceReferenceException expected) { - assertEquals("Failed to find serializer for Resource Reference [type = [test], parameters = []] and " - + "URL format [standard]", expected.getMessage()); - } + Throwable exception = assertThrows(UnsupportedResourceReferenceException.class, () -> { + this.serializer.serialize(resource); + }); + assertEquals("Failed to find serializer for Resource Reference [type = [test], parameters = []] and " + + "URL format [standard]", exception.getMessage()); } } \ No newline at end of file From 5e10fb9d595c9cec79ae8a45faffdc56443d6424 Mon Sep 17 00:00:00 2001 From: Marius Dumitru Florea Date: Fri, 9 Feb 2024 18:07:04 +0200 Subject: [PATCH 3/3] XWIKI-21763: Disable the server-side image resizing while exporting to PDF * Using a workaround until we add support for temporarily overwrite properties from a configuration source. * Small refactoring of PDFExportJob to reduce class-fan-out complexity --- .../internal/job/AbstractPDFExportJob.java | 89 +++++++++++++++++++ .../export/pdf/internal/job/PDFExportJob.java | 56 +----------- .../PDFExportIT/Parent/Child/WebHome.xml | 10 ++- .../pom.xml | 7 ++ .../org/xwiki/export/pdf/test/ui/AllIT.java | 3 +- .../xwiki/export/pdf/test/ui/PDFExportIT.java | 16 +++- .../main/resources/XWiki/PDFExport/Sheet.xml | 32 +++++++ .../XWiki/PDFExport/Translations.ko.xml | 2 +- 8 files changed, 154 insertions(+), 61 deletions(-) create mode 100644 xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-api/src/main/java/org/xwiki/export/pdf/internal/job/AbstractPDFExportJob.java diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-api/src/main/java/org/xwiki/export/pdf/internal/job/AbstractPDFExportJob.java b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-api/src/main/java/org/xwiki/export/pdf/internal/job/AbstractPDFExportJob.java new file mode 100644 index 000000000000..ce86d3d9e19d --- /dev/null +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-api/src/main/java/org/xwiki/export/pdf/internal/job/AbstractPDFExportJob.java @@ -0,0 +1,89 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.xwiki.export.pdf.internal.job; + +import java.util.Arrays; + +import javax.inject.Inject; + +import org.xwiki.export.pdf.job.PDFExportJobRequest; +import org.xwiki.export.pdf.job.PDFExportJobStatus; +import org.xwiki.job.AbstractJob; +import org.xwiki.job.GroupedJob; +import org.xwiki.job.JobGroupPath; +import org.xwiki.model.reference.EntityReference; +import org.xwiki.security.authorization.AuthorizationManager; +import org.xwiki.security.authorization.Right; + +/** + * Base class for PDF export job. + * + * @version $Id$ + */ +public abstract class AbstractPDFExportJob extends AbstractJob + implements GroupedJob +{ + /** + * The PDF export job type. + */ + public static final String JOB_TYPE = "export/pdf"; + + /** + * Used to check access permissions. + * + * @see #hasAccess(Right, EntityReference) + */ + @Inject + private AuthorizationManager authorization; + + @Override + public String getType() + { + return JOB_TYPE; + } + + @Override + public JobGroupPath getGroupPath() + { + return new JobGroupPath(Arrays.asList("export", "pdf")); + } + + @Override + protected PDFExportJobStatus createNewStatus(PDFExportJobRequest request) + { + return new PDFExportJobStatus(getType(), request, this.observationManager, this.loggerManager); + } + + /** + * Check access rights taking into account the job request. + * + * @param right the access right to check + * @param reference the target entity reference + * @return return {@code true} if the current user or the entity author have the specified access right on the + * specified entity, depending on the job request + */ + protected boolean hasAccess(Right right, EntityReference reference) + { + return ((!this.request.isCheckRights() + || this.authorization.hasAccess(right, this.request.getUserReference(), reference)) + && (!this.request.isCheckAuthorRights() + || this.authorization.hasAccess(right, this.request.getAuthorReference(), reference))); + } +} diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-api/src/main/java/org/xwiki/export/pdf/internal/job/PDFExportJob.java b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-api/src/main/java/org/xwiki/export/pdf/internal/job/PDFExportJob.java index 7f0a090b6a19..ff742a3e62f6 100644 --- a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-api/src/main/java/org/xwiki/export/pdf/internal/job/PDFExportJob.java +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-api/src/main/java/org/xwiki/export/pdf/internal/job/PDFExportJob.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.Arrays; import java.util.List; import javax.inject.Inject; @@ -34,17 +33,11 @@ import org.xwiki.export.pdf.PDFPrinter; import org.xwiki.export.pdf.internal.RequiredSkinExtensionsRecorder; import org.xwiki.export.pdf.job.PDFExportJobRequest; -import org.xwiki.export.pdf.job.PDFExportJobStatus; import org.xwiki.export.pdf.job.PDFExportJobStatus.DocumentRenderingResult; -import org.xwiki.job.AbstractJob; -import org.xwiki.job.GroupedJob; -import org.xwiki.job.JobGroupPath; import org.xwiki.model.reference.DocumentReference; -import org.xwiki.model.reference.EntityReference; import org.xwiki.model.reference.ObjectPropertyReference; import org.xwiki.model.reference.ObjectReference; import org.xwiki.resource.temporary.TemporaryResourceStore; -import org.xwiki.security.authorization.AuthorizationManager; import org.xwiki.security.authorization.Right; /** @@ -56,21 +49,8 @@ */ @Component @Named(PDFExportJob.JOB_TYPE) -public class PDFExportJob extends AbstractJob implements GroupedJob +public class PDFExportJob extends AbstractPDFExportJob { - /** - * The PDF export job type. - */ - public static final String JOB_TYPE = "export/pdf"; - - /** - * Used to check access permissions. - * - * @see #hasAccess(Right, EntityReference) - */ - @Inject - private AuthorizationManager authorization; - @Inject private DocumentRenderer documentRenderer; @@ -94,24 +74,6 @@ public class PDFExportJob extends AbstractJob +[[image:attach:xwiki-logo.png||width="100"]] + +[[image:attach:xwiki-logo.png||width="100" class="force-server-side-resize"]] + +{{velocity}} +{{html}} +<img src="$doc.getAttachmentURL('xwiki-logo.png', 'download', 'height=50')" alt="XWiki Logo" /> +{{/html}} +{{/velocity}} xwiki-logo.png image/png diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/pom.xml b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/pom.xml index 45ac8df77bfb..70133083f16f 100644 --- a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/pom.xml +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/pom.xml @@ -69,6 +69,13 @@ ${project.version} runtime + + + org.xwiki.platform + xwiki-platform-image-processing-plugin + ${project.version} + runtime + org.xwiki.platform diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/AllIT.java b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/AllIT.java index f2a76b1cda04..24569481e85e 100644 --- a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/AllIT.java +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/AllIT.java @@ -46,7 +46,8 @@ // Starting or stopping the Office server requires PR (for the current user, on the main wiki reference). // Enabling debug logs also requires PR. "xwikiPropertiesAdditionalProperties=test.prchecker.excludePattern=" - + ".*:(XWiki\\.OfficeImporterAdmin|PDFExportIT\\.EnableDebugLogs)" + + ".*:(XWiki\\.OfficeImporterAdmin|PDFExportIT\\.EnableDebugLogs)", + "xwikiCfgPlugins=com.xpn.xwiki.plugin.image.ImagePlugin", } ) @ExtendWith(PDFExportExecutionCondition.class) diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/PDFExportIT.java b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/PDFExportIT.java index ab8057748fe0..180b95ef2b33 100644 --- a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/PDFExportIT.java +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-test/xwiki-platform-export-pdf-test-docker/src/test/it/org/xwiki/export/pdf/test/ui/PDFExportIT.java @@ -81,7 +81,8 @@ // Starting or stopping the Office server requires PR (for the current user, on the main wiki reference). // Enabling debug logs also requires PR. "xwikiPropertiesAdditionalProperties=test.prchecker.excludePattern=" - + ".*:(XWiki\\.OfficeImporterAdmin|PDFExportIT\\.EnableDebugLogs)" + + ".*:(XWiki\\.OfficeImporterAdmin|PDFExportIT\\.EnableDebugLogs)", + "xwikiCfgPlugins=com.xpn.xwiki.plugin.image.ImagePlugin", } ) @ExtendWith(PDFExportExecutionCondition.class) @@ -225,11 +226,20 @@ void exportAsPDF(TestUtils setup, TestConfiguration testConfiguration) throws Ex assertTrue(contentPageText.contains("Child\nSection 1\nContent of first section.\n"), "Child document content missing: " + contentPageText); - // The content of the child document shows an image. + // The content of the child document shows the same image multiple times. List contentPageImages = pdf.getImagesFromPage(3); - assertEquals(1, contentPageImages.size()); + assertEquals(3, contentPageImages.size()); + + // Verify the images included in the PDF are not resized server-side (we know the image width is specified + // in the source wiki syntax and we enabled the server-side image resize by default). assertEquals(512, contentPageImages.get(0).getRawWidth()); assertEquals(512, contentPageImages.get(0).getRawHeight()); + assertEquals(512, contentPageImages.get(2).getRawWidth()); + assertEquals(512, contentPageImages.get(2).getRawHeight()); + + // For the second image we force the server-side resize. + assertEquals(100, contentPageImages.get(1).getRawWidth()); + assertEquals(100, contentPageImages.get(1).getRawHeight()); } } diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Sheet.xml b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Sheet.xml index 329a765ce00e..55e2a14d203c 100644 --- a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Sheet.xml +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Sheet.xml @@ -822,6 +822,38 @@ require([ }).wrap("<span></span>"); }; + /** + * Removes the image size (width and height) from the image URL query string in order to prevent the server-side + * resize of the image, thus allowing the full size image to be included in the generated PDF. + */ + async function disableServerSideImageResize() { + const imageLoadPromises = [] + document.querySelectorAll('#xwikicontent img:not(.force-server-side-resize)').forEach(image => { + const imageURL = new URL(image.src); + const imageParams = imageURL.searchParams; + if (imageParams.has('width') || imageParams.has('height')) { + // Backup the original query string before we modify the image URL. + const oldImageQueryString = imageURL.search; + // The image size is specified in the URL which may trigger a server-side resize. We want the full image to be + // included in the PDF so let's remove these parameters. + imageParams.delete('width'); + imageParams.delete('height'); + const newImageQueryString = '?' + imageParams.toString(); + const newImageSrc = image.getAttribute('src').replace(oldImageQueryString, newImageQueryString); + // Create a promise for when the full size image is loaded. + imageLoadPromises.push(new Promise((resolve, reject) => { + image.addEventListener('load', resolve); + image.addEventListener('error', reject); + image.addEventListener('abort', resolve); + image.setAttribute('src', newImageSrc); + })); + } + }); + await Promise.allSettled(imageLoadPromises); + } + + pageReady.delayPageReady(disableServerSideImageResize(), 'Disable server-side image resize.'); + // Adjust the exported content before performing the print layout. pageReady.afterPageReady(() => { refactorAnchors(); diff --git a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Translations.ko.xml b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Translations.ko.xml index 9cdf8b94f0cd..f403d803ecbe 100644 --- a/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Translations.ko.xml +++ b/xwiki-platform-core/xwiki-platform-export/xwiki-platform-export-pdf/xwiki-platform-export-pdf-ui/src/main/resources/XWiki/PDFExport/Translations.ko.xml @@ -110,4 +110,4 @@ XWiki.PDFExport.ConfigurationClass_maxContentSize.hint=단일 PDF 내보내기 XWiki.PDFExport.ConfigurationClass_replaceFOP=FOP 교체 XWiki.PDFExport.ConfigurationClass_replaceFOP.hint=Apache Formatting Objects Processor(FOP)를 기반으로 이전 PDF 내보내기를 대체합니다. - +