Skip to content

Commit

Permalink
feat: Added the ability to select a BaselineCollection for bulk export (
Browse files Browse the repository at this point in the history
#301)

Refs: #285
  • Loading branch information
pbezliapovich authored Dec 5, 2024
1 parent f24a947 commit be22a6e
Show file tree
Hide file tree
Showing 23 changed files with 556 additions and 85 deletions.
65 changes: 65 additions & 0 deletions docs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,47 @@
]
}
},
"/api/projects/{projectId}/collections/{collectionId}/documents": {
"get": {
"operationId": "getDocumentsFromCollection",
"parameters": [
{
"description": "Project ID",
"in": "path",
"name": "projectId",
"required": true,
"schema": {
"type": "string"
}
},
{
"description": "Collection ID",
"in": "path",
"name": "collectionId",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/DocumentCollectionEntry"
}
}
},
"description": "Successfully retrieved the list of documents in the collection"
}
},
"summary": "Get documents from collection",
"tags": [
"Collections"
]
}
},
"/api/projects/{projectId}/name": {
"get": {
"operationId": "getProjectName",
Expand Down Expand Up @@ -1602,6 +1643,29 @@
},
"type": "object"
},
"DocumentCollectionEntry": {
"description": "Details about document from collection",
"properties": {
"documentName": {
"description": "The name of the document",
"type": "string"
},
"projectId": {
"description": "The unique identifier for the project",
"example": "elibrary",
"type": "string"
},
"revision": {
"description": "The revision of the document",
"type": "string"
},
"spaceId": {
"description": "The unique identifier of the space within the project",
"type": "string"
}
},
"type": "object"
},
"ExportParams": {
"properties": {
"attachmentsFilter": {
Expand Down Expand Up @@ -1640,6 +1704,7 @@
"documentType": {
"description": "Type of the document",
"enum": [
"BASELINE_COLLECTION",
"LIVE_DOC",
"LIVE_REPORT",
"TEST_RUN",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public byte[] convertToPdf(@NotNull ExportParams exportParams, @Nullable ExportM
case LIVE_REPORT -> documentDataHelper.getLiveReport(project, exportParams);
case TEST_RUN -> documentDataHelper.getTestRun(Objects.requireNonNull(project), exportParams);
case WIKI_PAGE -> documentDataHelper.getWikiPage(project, exportParams);
case BASELINE_COLLECTION -> throw new IllegalArgumentException("Unsupported document type: %s".formatted(exportParams.getDocumentType()));
};
}

Expand Down Expand Up @@ -175,21 +176,23 @@ public byte[] convertToPdf(@NotNull ExportParams exportParams, @Nullable ExportM
client = ClientBuilder.newClient();
WebTarget webTarget = client.target(webhookConfig.getUrl()).register(MultiPartFeature.class);

FormDataMultiPart multipart = new FormDataMultiPart();
multipart.bodyPart(new FormDataBodyPart("exportParams", new ObjectMapper().writeValueAsString(exportParams), MediaType.APPLICATION_JSON_TYPE));
multipart.bodyPart(new FormDataBodyPart("html", htmlContent.getBytes(StandardCharsets.UTF_8), MediaType.APPLICATION_OCTET_STREAM_TYPE));
try (FormDataMultiPart multipart = new FormDataMultiPart()) {

Invocation.Builder requestBuilder = webTarget.request(MediaType.TEXT_PLAIN);
multipart.bodyPart(new FormDataBodyPart("exportParams", new ObjectMapper().writeValueAsString(exportParams), MediaType.APPLICATION_JSON_TYPE));
multipart.bodyPart(new FormDataBodyPart("html", htmlContent.getBytes(StandardCharsets.UTF_8), MediaType.APPLICATION_OCTET_STREAM_TYPE));

addAuthHeader(webhookConfig, requestBuilder);
Invocation.Builder requestBuilder = webTarget.request(MediaType.TEXT_PLAIN);

try (Response response = requestBuilder.post(Entity.entity(multipart, multipart.getMediaType()))) {
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
try (InputStream inputStream = response.readEntity(InputStream.class)) {
return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
addAuthHeader(webhookConfig, requestBuilder);

try (Response response = requestBuilder.post(Entity.entity(multipart, multipart.getMediaType()))) {
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
try (InputStream inputStream = response.readEntity(InputStream.class)) {
return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
}
} else {
logger.error(String.format("Could not get proper response from webhook [%s]: response status %s", webhookConfig.getUrl(), response.getStatus()));
}
} else {
logger.error(String.format("Could not get proper response from webhook [%s]: response status %s", webhookConfig.getUrl(), response.getStatus()));
}
}
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import ch.sbb.polarion.extension.generic.rest.GenericRestApplication;
import ch.sbb.polarion.extension.generic.settings.NamedSettingsRegistry;
import ch.sbb.polarion.extension.pdf_exporter.converter.PdfConverterJobsCleaner;
import ch.sbb.polarion.extension.pdf_exporter.rest.controller.CollectionApiController;
import ch.sbb.polarion.extension.pdf_exporter.rest.controller.CollectionInternalController;
import ch.sbb.polarion.extension.pdf_exporter.rest.controller.ConverterApiController;
import ch.sbb.polarion.extension.pdf_exporter.rest.controller.ConverterInternalController;
import ch.sbb.polarion.extension.pdf_exporter.rest.controller.SettingsApiController;
Expand Down Expand Up @@ -68,6 +70,8 @@ public PdfExporterRestApplication() {
new SettingsInternalController(),
new TestRunAttachmentsApiController(),
new TestRunAttachmentsInternalController(),
new CollectionApiController(),
new CollectionInternalController(),
new UtilityResourcesApiController(),
new UtilityResourcesInternalController()
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ch.sbb.polarion.extension.pdf_exporter.rest.controller;

import ch.sbb.polarion.extension.generic.rest.filter.Secured;
import ch.sbb.polarion.extension.generic.service.PolarionService;
import ch.sbb.polarion.extension.pdf_exporter.rest.model.collections.DocumentCollectionEntry;

import javax.ws.rs.Path;
import java.util.List;

@Secured
@Path("/api")
public class CollectionApiController extends CollectionInternalController {
private static final PolarionService polarionService = new PolarionService();

@Override
public List<DocumentCollectionEntry> getDocumentsFromCollection(String projectId, String collectionId) {
return polarionService.callPrivileged(() -> super.getDocumentsFromCollection(projectId, collectionId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package ch.sbb.polarion.extension.pdf_exporter.rest.controller;


import ch.sbb.polarion.extension.pdf_exporter.rest.model.collections.DocumentCollectionEntry;
import ch.sbb.polarion.extension.pdf_exporter.service.PdfExporterPolarionService;
import com.polarion.alm.shared.api.transaction.TransactionalExecutor;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.List;

@Hidden
@Path("/internal")
@Tag(name = "Collections")
public class CollectionInternalController {
private final PdfExporterPolarionService pdfExporterPolarionService;

public CollectionInternalController() {
pdfExporterPolarionService = new PdfExporterPolarionService();
}

@GET
@Path("/projects/{projectId}/collections/{collectionId}/documents")
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Get documents from collection",
responses = {
@ApiResponse(responseCode = "200",
description = "Successfully retrieved the list of documents in the collection",
content = @Content(schema = @Schema(implementation = DocumentCollectionEntry.class))
)
}
)
public List<DocumentCollectionEntry> getDocumentsFromCollection(@Parameter(description = "Project ID", required = true) @PathParam("projectId") String projectId,
@Parameter(description = "Collection ID", required = true) @PathParam("collectionId") String collectionId) {
return TransactionalExecutor.executeSafelyInReadOnlyTransaction(transaction -> pdfExporterPolarionService.getDocumentsFromCollection(projectId, collectionId, transaction));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,9 @@ private void validateExportParameters(ExportParams exportParams) {
if (exportParams.getLocationPath() == null && exportParams.getDocumentType() != DocumentType.TEST_RUN) {
throw new BadRequestException("Parameter 'locationPath' should be provided");
}
if (exportParams.getDocumentType() == DocumentType.BASELINE_COLLECTION) {
throw new BadRequestException("Parameter 'documentType' should not be 'BASELINE_COLLECTION'");
}
}

private String getFileName(@Nullable ExportParams exportParams) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ch.sbb.polarion.extension.pdf_exporter.rest.model.collections;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "Details about document from collection")
public class DocumentCollectionEntry {
@Schema(description = "The unique identifier for the project", example = "elibrary")
private String projectId;

@Schema(description = "The unique identifier of the space within the project")
private String spaceId;

@Schema(description = "The name of the document")
private String documentName;

@Schema(description = "The revision of the document")
private String revision;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

@Schema(description = "Type of the document")
public enum DocumentType {
@Schema(description = "Baseline collection")
BASELINE_COLLECTION,

@Schema(description = "Live document")
LIVE_DOC,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,22 @@
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.StylePackageModel;
import ch.sbb.polarion.extension.pdf_exporter.rest.model.settings.stylepackage.StylePackageWeightInfo;
import ch.sbb.polarion.extension.pdf_exporter.settings.StylePackageSettings;
import ch.sbb.polarion.extension.pdf_exporter.util.WildcardUtils;
import com.polarion.alm.projects.IProjectService;
import com.polarion.alm.shared.api.model.baselinecollection.BaselineCollectionReference;
import com.polarion.alm.shared.api.transaction.ReadOnlyTransaction;
import com.polarion.alm.tracker.ITestManagementService;
import com.polarion.alm.tracker.ITrackerService;
import com.polarion.alm.tracker.model.IModule;
import com.polarion.alm.tracker.model.ITestRun;
import com.polarion.alm.tracker.model.ITestRunAttachment;
import com.polarion.alm.tracker.model.ITrackerProject;
import com.polarion.alm.tracker.model.baselinecollection.IBaselineCollection;
import com.polarion.alm.tracker.model.baselinecollection.IBaselineCollectionElement;
import com.polarion.core.util.StringUtils;
import com.polarion.platform.IPlatformService;
import com.polarion.platform.persistence.IDataService;
Expand Down Expand Up @@ -115,7 +120,7 @@ private boolean isStylePackageSuitable(@Nullable String projectId, @NotNull Stri
return true;
} else {
IDataService dataService = getTrackerService().getDataService();
IPObjectList<IModule> suitableDocuments = dataService.searchInstances(dataService.getPrototype("Module"), model.getMatchingQuery(), "name");
IPObjectList<IModule> suitableDocuments = dataService.searchInstances(IModule.PROTO, model.getMatchingQuery(), "name");
for (IModule suitableDocument : suitableDocuments) {
if (sameDocument(projectId, spaceId, documentName, suitableDocument)) {
return true;
Expand Down Expand Up @@ -165,4 +170,30 @@ private boolean sameDocument(@Nullable String projectId, @NotNull String spaceId
}
return testRunAttachment;
}

public @NotNull List<DocumentCollectionEntry> getDocumentsFromCollection(@NotNull String projectId, @NotNull String collectionId, @NotNull ReadOnlyTransaction transaction) {
List<DocumentCollectionEntry> result = new ArrayList<>();

IBaselineCollection collection = new BaselineCollectionReference(projectId, collectionId).get(transaction).getOldApi();

List<IModule> modules = collection.getElements().stream()
.map(IBaselineCollectionElement::getObjectWithRevision)
.filter(IModule.class::isInstance)
.map(IModule.class::cast)
.toList();

for (IModule module : modules) {
String[] locationParts = module.getModuleLocation().getLocationPath().split("/");
if (locationParts.length == 2) {
result.add(new DocumentCollectionEntry(
module.getProjectId(),
locationParts[0],
locationParts[1],
module.getRevision()
));
}
}

return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ public DocumentData<ITestRun> getTestRun(@NotNull ITrackerProject project, @NotN
});
}


public DocumentData<IWikiPage> getWikiPage(@Nullable ITrackerProject project, @NotNull ExportParams exportParams) {
return getWikiPage(project, exportParams, true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.jetbrains.annotations.VisibleForTesting;

import java.util.EnumSet;
import java.util.Objects;


public class DocumentFileNameHelper {
Expand Down Expand Up @@ -46,10 +47,11 @@ public String getDocumentFileName(@NotNull ExportParams exportParams) {
DocumentDataHelper documentDataHelper = new DocumentDataHelper(pdfExporterPolarionService);
final DocumentData<? extends IUniqueObject> documentData =
switch (exportParams.getDocumentType()) {
case LIVE_DOC -> documentDataHelper.getLiveDoc(project, exportParams, false);
case LIVE_DOC -> documentDataHelper.getLiveDoc(Objects.requireNonNull(project), exportParams, false);
case LIVE_REPORT -> documentDataHelper.getLiveReport(project, exportParams, false);
case TEST_RUN -> documentDataHelper.getTestRun(project, exportParams, false);
case TEST_RUN -> documentDataHelper.getTestRun(Objects.requireNonNull(project), exportParams, false);
case WIKI_PAGE -> documentDataHelper.getWikiPage(project, exportParams, false);
case BASELINE_COLLECTION -> throw new IllegalArgumentException("Unsupported document type: %s".formatted(exportParams.getDocumentType()));
};

FileNameTemplateModel fileNameTemplateModel = getFileNameTemplateModel(ScopeUtils.getScopeFromProject(exportParams.getProjectId()));
Expand All @@ -70,16 +72,14 @@ public String getDocumentFileName(@NotNull ExportParams exportParams) {
return fileName.replaceAll("[\\\\/:*?\"<>|]", "_");
}

private @NotNull String getFileNameTemplate(@NotNull DocumentType documentType, @NotNull FileNameTemplateModel fileNameTemplateModel) {
@VisibleForTesting
@NotNull String getFileNameTemplate(@NotNull DocumentType documentType, @NotNull FileNameTemplateModel fileNameTemplateModel) {
return switch (documentType) {
case LIVE_DOC:
yield fileNameTemplateModel.getDocumentNameTemplate();
case LIVE_REPORT:
yield fileNameTemplateModel.getReportNameTemplate();
case TEST_RUN:
yield fileNameTemplateModel.getTestRunNameTemplate();
case WIKI_PAGE:
yield fileNameTemplateModel.getWikiNameTemplate();
case LIVE_DOC -> fileNameTemplateModel.getDocumentNameTemplate();
case LIVE_REPORT -> fileNameTemplateModel.getReportNameTemplate();
case TEST_RUN -> fileNameTemplateModel.getTestRunNameTemplate();
case WIKI_PAGE -> fileNameTemplateModel.getWikiNameTemplate();
case BASELINE_COLLECTION -> throw new IllegalArgumentException("Unsupported document type: %s".formatted(documentType));
};
}

Expand Down
Loading

0 comments on commit be22a6e

Please sign in to comment.