diff --git a/docs/openapi.json b/docs/openapi.json index f17b5435..e7c064fd 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -1027,37 +1027,28 @@ } }, "/api/settings/style-package/suitable-names": { - "get": { + "post": { "operationId": "getSuitableStylePackageNames", - "parameters": [ - { - "in": "query", - "name": "projectId", - "schema": { - "type": "string" - } - }, - { - "in": "query", - "name": "spaceId", - "schema": { - "type": "string" + "requestBody": { + "content": { + "application/json": { + "schema": { + "items": { + "$ref": "#/components/schemas/DocIdentifier" + }, + "type": "array" + } } }, - { - "in": "query", - "name": "documentName", - "schema": { - "type": "string" - } - } - ], + "description": "List of document identifiers", + "required": true + }, "responses": { "200": { "description": "Successfully retrieved the list of style package names" } }, - "summary": "Get list of style packages suitable for a document", + "summary": "Get list of style packages suitable for the specified list of documents (sorted by weight)", "tags": [ "Settings" ] @@ -1611,6 +1602,24 @@ }, "type": "object" }, + "DocIdentifier": { + "description": "Unique document identifier data", + "properties": { + "documentName": { + "description": "Document name", + "type": "string" + }, + "projectId": { + "description": "Project ID", + "type": "string" + }, + "spaceId": { + "description": "Space ID", + "type": "string" + } + }, + "type": "object" + }, "DocumentCollectionEntry": { "description": "Details about document from collection", "properties": { diff --git a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/PdfExporterFormExtension.java b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/PdfExporterFormExtension.java index 463f143e..76120296 100644 --- a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/PdfExporterFormExtension.java +++ b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/PdfExporterFormExtension.java @@ -9,6 +9,7 @@ import ch.sbb.polarion.extension.pdf_exporter.rest.model.conversion.DocumentType; import ch.sbb.polarion.extension.pdf_exporter.rest.model.conversion.ExportParams; import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.localization.Language; +import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.DocIdentifier; import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.StylePackageModel; import ch.sbb.polarion.extension.pdf_exporter.service.PdfExporterPolarionService; import ch.sbb.polarion.extension.pdf_exporter.service.PolarionBaselineExecutor; @@ -173,7 +174,7 @@ private Collection getSuitableStylePackages(@NotNull IModule module } else { documentName = locationPath; } - return polarionService.getSuitableStylePackages(module.getProject().getId(), spaceId, documentName); + return polarionService.getSuitableStylePackages(List.of(new DocIdentifier(module.getProject().getId(), spaceId, documentName))); } private Collection getSettingNames(@NotNull String featureName, @NotNull String scope) { diff --git a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/rest/controller/SettingsApiController.java b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/rest/controller/SettingsApiController.java index e270b41a..9c109fc4 100644 --- a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/rest/controller/SettingsApiController.java +++ b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/rest/controller/SettingsApiController.java @@ -3,6 +3,7 @@ import ch.sbb.polarion.extension.generic.rest.filter.Secured; import ch.sbb.polarion.extension.generic.service.PolarionService; import ch.sbb.polarion.extension.generic.settings.SettingName; +import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.DocIdentifier; import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.StylePackageWeightInfo; import org.glassfish.jersey.media.multipart.FormDataBodyPart; @@ -44,8 +45,8 @@ public void deleteImages(String coverPageName, String scope) { } @Override - public Collection getSuitableStylePackageNames(String projectId, String spaceId, String documentName) { - return polarionService.callPrivileged(() -> super.getSuitableStylePackageNames(projectId, spaceId, documentName)); + public Collection getSuitableStylePackageNames(List docIdentifiers) { + return polarionService.callPrivileged(() -> super.getSuitableStylePackageNames(docIdentifiers)); } @Override diff --git a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/rest/controller/SettingsInternalController.java b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/rest/controller/SettingsInternalController.java index b303febd..52c4dcda 100644 --- a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/rest/controller/SettingsInternalController.java +++ b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/rest/controller/SettingsInternalController.java @@ -4,6 +4,7 @@ import ch.sbb.polarion.extension.generic.settings.SettingName; import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.coverpage.CoverPageModel; import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.localization.LocalizationModel; +import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.DocIdentifier; import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.StylePackageWeightInfo; import ch.sbb.polarion.extension.pdf_exporter.service.PdfExporterPolarionService; import ch.sbb.polarion.extension.pdf_exporter.settings.CoverPageSettings; @@ -143,20 +144,27 @@ public void deleteImages(@PathParam("name") String coverPageName, @QueryParam("s new CoverPageSettings().deleteCoverPageImages(coverPageName, scope); } - @GET + @POST @Path("/settings/style-package/suitable-names") + @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @Tag(name = "Settings") - @Operation(summary = "Get list of style packages suitable for a document", + @Operation(summary = "Get list of style packages suitable for the specified list of documents (sorted by weight)", + requestBody = @RequestBody(description = "List of document identifiers", + required = true, + content = @Content(array = @ArraySchema(schema = @Schema(implementation = DocIdentifier.class)), + mediaType = MediaType.APPLICATION_JSON + ) + ), responses = { @ApiResponse(responseCode = "200", description = "Successfully retrieved the list of style package names") } ) - public Collection getSuitableStylePackageNames(@QueryParam("projectId") String projectId, @QueryParam("spaceId") String spaceId, @QueryParam("documentName") String documentName) { - if (spaceId == null || documentName == null) { - throw new BadRequestException("Parameters 'spaceId' and 'documentName' are required'"); + public Collection getSuitableStylePackageNames(List docIdentifiers) { + if (docIdentifiers.isEmpty()) { + throw new BadRequestException("At least one document identifier required"); } - return pdfExporterPolarionService.getSuitableStylePackages(projectId, spaceId, documentName); + return pdfExporterPolarionService.getSuitableStylePackages(docIdentifiers); } @GET diff --git a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/rest/model/settings/stylepackage/DocIdentifier.java b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/rest/model/settings/stylepackage/DocIdentifier.java new file mode 100644 index 00000000..eb9edb56 --- /dev/null +++ b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/rest/model/settings/stylepackage/DocIdentifier.java @@ -0,0 +1,37 @@ +package ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; +import org.jetbrains.annotations.NotNull; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(description = "Unique document identifier data") +public class DocIdentifier { + + @Schema( + description = "Project ID" + ) + private @NotNull String projectId; + + @Schema( + description = "Space ID" + ) + private @NotNull String spaceId; + + @Schema( + description = "Document name" + ) + private @NotNull String documentName; +} diff --git a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/service/PdfExporterPolarionService.java b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/service/PdfExporterPolarionService.java index 8f2c8a72..a8d617e0 100644 --- a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/service/PdfExporterPolarionService.java +++ b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/service/PdfExporterPolarionService.java @@ -1,12 +1,14 @@ package ch.sbb.polarion.extension.pdf_exporter.service; import ch.sbb.polarion.extension.generic.service.PolarionService; +import ch.sbb.polarion.extension.generic.settings.GenericNamedSettings; import ch.sbb.polarion.extension.generic.settings.NamedSettingsRegistry; import ch.sbb.polarion.extension.generic.settings.SettingId; import ch.sbb.polarion.extension.generic.settings.SettingName; import ch.sbb.polarion.extension.generic.util.ScopeUtils; import ch.sbb.polarion.extension.pdf_exporter.rest.model.attachments.TestRunAttachment; import ch.sbb.polarion.extension.pdf_exporter.rest.model.collections.DocumentCollectionEntry; +import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.DocIdentifier; import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.StylePackageModel; import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.StylePackageWeightInfo; import ch.sbb.polarion.extension.pdf_exporter.settings.StylePackageSettings; @@ -100,10 +102,13 @@ public void updateStylePackagesWeights(@NotNull List wei } } - public Collection getSuitableStylePackages(@Nullable String projectId, @NotNull String spaceId, @NotNull String documentName) { + public Collection getSuitableStylePackages(List docIdentifiers) { StylePackageSettings stylePackageSettings = (StylePackageSettings) NamedSettingsRegistry.INSTANCE.getByFeatureName(StylePackageSettings.FEATURE_NAME); - Collection stylePackageNames = stylePackageSettings.readNames(ScopeUtils.getScopeFromProject(projectId)); - List names = stylePackageNames.stream().filter(stylePackageName -> isStylePackageSuitable(projectId, spaceId, documentName, stylePackageSettings, stylePackageName)).toList(); + // if user mixes items from different projects then we can use only 'default'-level style packages + boolean multipleProjects = docIdentifiers.stream().map(DocIdentifier::getProjectId).distinct().count() > 1; + Collection stylePackageNames = stylePackageSettings.readNames(ScopeUtils.getScopeFromProject(multipleProjects ? GenericNamedSettings.DEFAULT_SCOPE : docIdentifiers.get(0).getProjectId())); + List names = stylePackageNames.stream().filter(stylePackageName -> docIdentifiers.stream().allMatch( + i -> isStylePackageSuitable(i.getProjectId(), i.getSpaceId(), i.getDocumentName(), stylePackageSettings, stylePackageName))).toList(); Map weightsMap = new HashMap<>(); names.forEach(name -> weightsMap.put(name, stylePackageSettings.read(name.getScope(), SettingId.fromName(name.getName()), null).getWeight())); return names.stream().sorted((o1, o2) -> { diff --git a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/widgets/BulkPdfExportWidgetRenderer.java b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/widgets/BulkPdfExportWidgetRenderer.java index e6615126..448d7ba5 100644 --- a/src/main/java/ch/sbb/polarion/extension/pdf_exporter/widgets/BulkPdfExportWidgetRenderer.java +++ b/src/main/java/ch/sbb/polarion/extension/pdf_exporter/widgets/BulkPdfExportWidgetRenderer.java @@ -1,6 +1,7 @@ package ch.sbb.polarion.extension.pdf_exporter.widgets; import ch.sbb.polarion.extension.pdf_exporter.rest.model.conversion.DocumentType; +import com.polarion.alm.projects.internal.model.Project; import com.polarion.alm.server.api.model.rp.widget.AbstractWidgetRenderer; import com.polarion.alm.server.api.model.rp.widget.BottomQueryLinksBuilder; import com.polarion.alm.shared.api.model.ModelObject; @@ -164,6 +165,7 @@ private void renderItem(@NotNull HtmlContentBuilder builder, @NotNull ModelObjec checkbox.attributes() .byName("type", "checkbox") .byName("data-type", item.getOldApi().getPrototype().getName()) + .byName("data-project", getProject(item)) .byName("data-space", getSpace(item)) .byName("data-id", getValue(item, "id")) .className("export-item"); @@ -193,6 +195,10 @@ private String getSpace(@NotNull ModelObject item) { } } + private String getProject(@NotNull ModelObject item) { + return item.getOldApi().getValue("project") instanceof Project project ? project.getId() : ""; + } + private String getValue(@NotNull ModelObject item, @NotNull String fieldName) { Object fieldValue = item.getOldApi().getValue(fieldName); return fieldValue == null ? "" : fieldValue.toString(); diff --git a/src/main/resources/webapp/pdf-exporter/js/bulk-pdf-exporter.js b/src/main/resources/webapp/pdf-exporter/js/bulk-pdf-exporter.js index 8782a9f3..3ab9f8c4 100644 --- a/src/main/resources/webapp/pdf-exporter/js/bulk-pdf-exporter.js +++ b/src/main/resources/webapp/pdf-exporter/js/bulk-pdf-exporter.js @@ -65,6 +65,7 @@ const BulkPdfExporter = { const div = document.createElement("div"); div.className = "export-item paused"; div.dataset["type"] = selectedCheckbox.dataset["type"]; + div.dataset["project"] = selectedCheckbox.dataset["project"]; div.dataset["space"] = selectedCheckbox.dataset["space"]; div.dataset["id"] = selectedCheckbox.dataset["id"]; @@ -211,6 +212,7 @@ const BulkPdfExporter = { currentItem.classList.add("in-progress"); const documentType = this.getDocumentType(currentItem.dataset["type"]); + this.exportParams["projectId"] = `${currentItem.dataset["project"]}`; this.exportParams["documentType"] = documentType; const documentId = currentItem.dataset["id"]; if (documentType === ExportParams.DocumentType.TEST_RUN) { diff --git a/src/main/resources/webapp/pdf-exporter/js/pdf-exporter.js b/src/main/resources/webapp/pdf-exporter/js/pdf-exporter.js index a6feb873..b6162f1b 100644 --- a/src/main/resources/webapp/pdf-exporter/js/pdf-exporter.js +++ b/src/main/resources/webapp/pdf-exporter/js/pdf-exporter.js @@ -141,11 +141,13 @@ const PdfExporter = { }); }, - loadSettingNames: function ({setting, scope, selectElement, customUrl}) { + loadSettingNames: function ({setting, scope, selectElement, customUrl, customMethod, customBody, customContentType}) { return new Promise((resolve, reject) => { this.callAsync({ - method: "GET", + method: customMethod ? customMethod : "GET", url: customUrl ? customUrl : `/polarion/pdf-exporter/rest/internal/settings/${setting}/names?scope=${scope}`, + body: customBody ? customBody : undefined, + contentType: customContentType ? customContentType : undefined, responseType: "json", }).then(({response}) => { selectElement.innerHTML = ""; // Clear previously loaded content @@ -248,20 +250,26 @@ const PdfExporter = { }, loadStylePackages: function (exportContext) { - let stylePackagesUrl; + let stylePackagesUrl = `/polarion/pdf-exporter/rest/internal/settings/style-package/suitable-names`; + const docIdentifiers = []; if (exportContext.getExportType() === ExportParams.ExportType.BULK) { - stylePackagesUrl = `/polarion/pdf-exporter/rest/internal/settings/style-package/names?scope=${exportContext.getScope()}`; + this.exportContext.bulkExportWidget.querySelectorAll('input[type="checkbox"]:not(.export-all):checked').forEach((selectedCheckbox) => { + docIdentifiers.push({ + projectId: selectedCheckbox.dataset["project"], spaceId: selectedCheckbox.dataset["space"], documentName: selectedCheckbox.dataset["id"] + }); + }); } else { - stylePackagesUrl = `/polarion/pdf-exporter/rest/internal/settings/style-package/suitable-names` - + `?spaceId=${exportContext.getSpaceId()}&documentName=${exportContext.getDocumentName()}`; - if (exportContext.getProjectId()) { - stylePackagesUrl += `&projectId=${exportContext.getProjectId()}` - } + docIdentifiers.push({ + projectId: `${exportContext.getProjectId()}`, spaceId: `${exportContext.getSpaceId()}`, documentName: `${exportContext.getDocumentName()}` + }); } return this.loadSettingNames({ customUrl: stylePackagesUrl, - selectElement: document.getElementById("popup-style-package-select") + selectElement: document.getElementById("popup-style-package-select"), + customMethod: 'POST', + customBody: JSON.stringify(docIdentifiers), + customContentType: 'application/json' }).then(() => { const stylePackageSelect = document.getElementById("popup-style-package-select"); const valueToPreselect = SbbCommon.getCookie(SELECTED_STYLE_PACKAGE_COOKIE); diff --git a/src/test/java/ch/sbb/polarion/extension/pdf_exporter/service/PdfExporterPolarionServiceTest.java b/src/test/java/ch/sbb/polarion/extension/pdf_exporter/service/PdfExporterPolarionServiceTest.java index e8165839..6acb620d 100644 --- a/src/test/java/ch/sbb/polarion/extension/pdf_exporter/service/PdfExporterPolarionServiceTest.java +++ b/src/test/java/ch/sbb/polarion/extension/pdf_exporter/service/PdfExporterPolarionServiceTest.java @@ -7,6 +7,7 @@ import ch.sbb.polarion.extension.generic.util.ScopeUtils; import ch.sbb.polarion.extension.pdf_exporter.rest.model.attachments.TestRunAttachment; import ch.sbb.polarion.extension.pdf_exporter.rest.model.collections.DocumentCollectionEntry; +import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.DocIdentifier; import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.StylePackageModel; import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.StylePackageWeightInfo; import ch.sbb.polarion.extension.pdf_exporter.settings.StylePackageSettings; @@ -161,7 +162,7 @@ void testGetSuitableStylePackages() { when(stylePackageSettings.read(eq("project/someProjectId/"), eq(SettingId.fromName("name4")), isNull())).thenReturn(mockModel4); when(stylePackageSettings.read(eq("project/someProjectId/"), eq(SettingId.fromName("name5")), isNull())).thenReturn(mockModel5); - Collection result = service.getSuitableStylePackages(projectId, spaceId, documentName); + Collection result = service.getSuitableStylePackages(List.of(new DocIdentifier(projectId, spaceId, documentName))); assertNotNull(result); assertEquals(5, result.size());