Skip to content

Commit

Permalink
feat: Extended REST API annotation (#182)
Browse files Browse the repository at this point in the history
Refs: #180

Co-authored-by: Sergey Grigoriev <sergey.grigoriev@sbb.ch>
  • Loading branch information
pbezliapovich and grigoriev authored Sep 2, 2024
1 parent 97ce5f4 commit 9a89ff6
Show file tree
Hide file tree
Showing 15 changed files with 1,728 additions and 1,609 deletions.
2,957 changes: 1,415 additions & 1,542 deletions docs/openapi.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
import ch.sbb.polarion.extension.pdf.exporter.util.configuration.WeasyPrintStatusProvider;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
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 org.jetbrains.annotations.NotNull;

import javax.ws.rs.DefaultValue;
Expand All @@ -27,47 +31,98 @@ public class ConfigurationInternalController {
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/configuration/default-settings")
@Operation(summary = "Checks default settings configuration")
@Operation(
summary = "Checks default settings configuration",
responses = {
@ApiResponse(responseCode = "200",
description = "Successfully retrieved default settings configuration",
content = @Content(schema = @Schema(implementation = ConfigurationStatus.class))
)
}
)
public @NotNull ConfigurationStatus checkDefaultSettings(@QueryParam("scope") @DefaultValue("") String scope) {
return new DefaultSettingsStatusProvider().getStatus(ConfigurationStatusProvider.Context.builder().scope(scope).build());
}

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/configuration/document-properties-pane-config")
@Operation(summary = "Checks document properties pane configuration")
@Operation(
summary = "Checks document properties pane configuration",
responses = {
@ApiResponse(responseCode = "200",
description = "Successfully retrieved document properties pane configuration",
content = @Content(schema = @Schema(implementation = ConfigurationStatus.class))
)
}
)
public @NotNull ConfigurationStatus checkDocumentPropertiesPaneConfig(@QueryParam("scope") @DefaultValue("") String scope) {
return new DocumentPropertiesPaneStatusProvider().getStatus(ConfigurationStatusProvider.Context.builder().scope(scope).build());
}

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/configuration/dle-toolbar-config")
@Operation(summary = "Checks DLE Toolbar configuration")
@Operation(
summary = "Checks DLE Toolbar configuration",
responses = {
@ApiResponse(responseCode = "200",
description = "Successfully retrieved DLE Toolbar configuration",
content = @Content(schema = @Schema(implementation = ConfigurationStatus.class))
)
}
)
public @NotNull ConfigurationStatus checkDleToolbarConfig() {
return new DleToolbarStatusProvider().getStatus(ConfigurationStatusProvider.Context.builder().build());
}

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/configuration/live-report-config")
@Operation(summary = "Checks Live Report configuration")
@Operation(
summary = "Checks Live Report configuration",
responses = {
@ApiResponse(responseCode = "200",
description = "Successfully retrieved Live Report configuration",
content = @Content(schema = @Schema(implementation = ConfigurationStatus.class))
)
}
)
public @NotNull ConfigurationStatus checkLiveReportConfig() {
return new LiveReportMainHeadStatusProvider().getStatus(ConfigurationStatusProvider.Context.builder().build());
}

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/configuration/cors-config")
@Operation(summary = "Checks CORS configuration")
@Operation(
summary = "Checks CORS configuration",
description = "Retrieves the status of the CORS configuration.",
responses = {
@ApiResponse(responseCode = "200",
description = "Successfully retrieved CORS configuration",
content = @Content(schema = @Schema(implementation = ConfigurationStatus.class))
)
}
)
public @NotNull ConfigurationStatus checkCORSConfig() {
return new CORSStatusProvider().getStatus(ConfigurationStatusProvider.Context.builder().build());
}

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/configuration/weasyprint")
@Operation(summary = "Checks WeasyPrint configuration")
@Operation(
summary = "Checks WeasyPrint configuration",
description = "Retrieves the status of the WeasyPrint configuration.",
responses = {
@ApiResponse(responseCode = "200",
description = "Successfully retrieved WeasyPrint configuration",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ConfigurationStatus.class)))
)
}
)

public @NotNull List<ConfigurationStatus> checkWeasyPrint() {
return new WeasyPrintStatusProvider().getStatuses(ConfigurationStatusProvider.Context.builder().build());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
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.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.jetbrains.annotations.VisibleForTesting;
Expand All @@ -30,7 +32,6 @@
import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
Expand All @@ -49,6 +50,7 @@

@Hidden
@Path("/internal")
@Tag(name = "PDF Processing")
@SuppressWarnings("java:S1200")
public class ConverterInternalController {

Expand Down Expand Up @@ -96,8 +98,13 @@ public ConverterInternalController() {
@Path("/convert")
@Consumes(MediaType.APPLICATION_JSON)
@Produces("application/pdf")
@Tag(name = "PDF Processing")
@Operation(summary = "Returns requested Polarion's document converted to PDF",
requestBody = @RequestBody(description = "Export parameters to generate the PDF",
required = true,
content = @Content(schema = @Schema(implementation = ExportParams.class),
mediaType = MediaType.APPLICATION_JSON
)
),
responses = {
@ApiResponse(responseCode = "200",
description = "Content of PDF document as a byte array",
Expand All @@ -114,8 +121,14 @@ public Response convertToPdf(ExportParams exportParams) {
@Path("/prepared-html-content")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_HTML)
@Tag(name = "PDF Processing")
@Operation(summary = "Returns prepared HTML which will be used for PDF conversion using WeasyPrint",
requestBody = @RequestBody(description = "Export parameters to generate the PDF",
required = true,
content = @Content(
schema = @Schema(implementation = ExportParams.class),
mediaType = MediaType.APPLICATION_JSON
)
),
responses = {
@ApiResponse(responseCode = "200",
description = "Prepared HTML content",
Expand All @@ -130,8 +143,13 @@ public String prepareHtmlContent(ExportParams exportParams) {
@POST
@Path("/convert/jobs")
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = "PDF Processing")
@Operation(summary = "Starts asynchronous conversion job of Polarion's document to PDF",
requestBody = @RequestBody(description = "Export parameters to generate the PDF",
required = true,
content = @Content(schema = @Schema(implementation = ExportParams.class),
mediaType = MediaType.APPLICATION_JSON
)
),
responses = {
@ApiResponse(responseCode = "202",
description = "Conversion process is started, job URI is returned in Location header"
Expand All @@ -149,21 +167,19 @@ public Response startPdfConverterJob(ExportParams exportParams) {
@GET
@Path("/convert/jobs/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = "PDF Processing")
@Operation(summary = "Returns PDF conversion job status",
responses = {
// OpenAPI response MediaTypes for 303 and 202 response codes are generic to satisfy automatic redirect in SwaggerUI
@ApiResponse(responseCode = "303",
description = "Conversion job is finished successfully, Location header contains result URL",
content = {@Content(mediaType = "application/*")}
content = {@Content(mediaType = "application/*", schema = @Schema(implementation = ConverterJobDetails.class))}
),
@ApiResponse(responseCode = "202",
description = "Conversion job is still in progress",
content = {@Content(mediaType = "application/*")}
content = {@Content(mediaType = "application/*", schema = @Schema(implementation = ConverterJobDetails.class))}
),
@ApiResponse(responseCode = "409",
description = "Conversion job is failed or cancelled",
content = {@Content(mediaType = MediaType.APPLICATION_JSON)}
description = "Conversion job is failed or cancelled"
),
@ApiResponse(responseCode = "404",
description = "Conversion job id is unknown"
Expand Down Expand Up @@ -192,7 +208,6 @@ public Response getPdfConverterJobStatus(@PathParam("id") String jobId) {
@GET
@Path("/convert/jobs/{id}/result")
@Produces("application/pdf")
@Tag(name = "PDF Processing")
@Operation(summary = "Returns PDF conversion job result",
responses = {
@ApiResponse(responseCode = "200",
Expand Down Expand Up @@ -220,12 +235,11 @@ public Response getPdfConverterJobResult(@PathParam("id") String jobId) {
@GET
@Path("/convert/jobs")
@Produces("application/json")
@Tag(name = "PDF Processing")
@Operation(summary = "Returns all active PDF conversion jobs statuses",
responses = {
@ApiResponse(responseCode = "200",
description = "Conversion jobs statuses",
content = {@Content(mediaType = "application/json")}
content = {@Content(mediaType = "application/json", schema = @Schema(implementation = Map.class))}
)
})
public Response getAllPdfConverterJobs() {
Expand All @@ -243,7 +257,6 @@ public Response getAllPdfConverterJobs() {
@Path("/convert/html")
@Consumes(MediaType.TEXT_HTML)
@Produces("application/pdf")
@Tag(name = "PDF Processing")
@Operation(summary = "Converts input HTML to PDF",
responses = {
@ApiResponse(responseCode = "200",
Expand All @@ -265,8 +278,13 @@ public Response convertHtmlToPdf(
@Path("/validate")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = "PDF Processing")
@Operation(summary = "Validates if requested Polarion's document been converted to PDF doesn't contain pages which content exceeds page's width")
@Operation(summary = "Validates if requested Polarion's document been converted to PDF doesn't contain pages which content exceeds page's width",
responses = {
@ApiResponse(responseCode = "200",
description = "Validation result",
content = {@Content(mediaType = "application/json", schema = @Schema(implementation = WidthValidationResult.class))}
)
})
public WidthValidationResult validatePdfWidth(
ExportParams exportParams,
@Parameter(description = "Limit of 'invalid' pages in response", required = true) @QueryParam("max-results") int maxResults) {
Expand All @@ -280,16 +298,26 @@ public WidthValidationResult validatePdfWidth(
@Path("/checknestedlists")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = "PDF Processing")
@Operation(summary = "Checks whether document contains nested lists")
@Operation(
summary = "Checks whether document contains nested lists",
requestBody = @RequestBody(
description = "Export parameters used to locate and check the document for nested lists",
required = true,
content = @Content(schema = @Schema(implementation = ExportParams.class)
)
),
responses = {
@ApiResponse(
responseCode = "200",
description = "Check completed successfully, returning whether nested lists are present",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = NestedListsCheck.class))
)
}
)
@SuppressWarnings("java:S1166")
public NestedListsCheck checkNestedLists(ExportParams exportParams) {
try {
boolean containsNestedLists = liveDocHelper.documentContainsNestedNumberedLists(exportParams);
return NestedListsCheck.builder().containsNestedLists(containsNestedLists).build();
} catch (Exception e) {
throw new InternalServerErrorException(e.getMessage());
}
boolean containsNestedLists = liveDocHelper.documentContainsNestedNumberedLists(exportParams);
return NestedListsCheck.builder().containsNestedLists(containsNestedLists).build();
}

private void validateExportParameters(ExportParams exportParams) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import ch.sbb.polarion.extension.pdf.exporter.util.LocalizationHelper;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import net.sf.okapi.lib.xliff2.reader.XLIFFReader;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
Expand Down Expand Up @@ -37,16 +39,21 @@

@Hidden
@Path("/internal")
@Tag(name = "Settings", description = "Operations related to PDF-exporter settings management")
@SecurityRequirement(name = "bearerAuth")
public class SettingsInternalController {

private Set<String> predefinedCoverPageTemplates;
private final PdfExporterPolarionService pdfExporterPolarionService = new PdfExporterPolarionService();
private Set<String> predefinedCoverPageTemplates;

@GET
@Path("/settings/localization/names/{name}/download")
@Produces(MediaType.APPLICATION_XML)
@Tag(name = "Settings")
@Operation(summary = "Downloads localization values by name of localization settings")
@Operation(summary = "Downloads localization values by name of localization settings",
responses = {
@ApiResponse(responseCode = "200", description = "Localization file downloaded successfully")
}
)
public Response downloadTranslations(
@PathParam("name") String name,
@QueryParam("language") String language,
Expand All @@ -67,8 +74,11 @@ public Response downloadTranslations(
@Path("/settings/localization/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = "Settings")
@Operation(summary = "Uploads localization values")
@Operation(summary = "Uploads localization values",
responses = {
@ApiResponse(responseCode = "200", description = "Localization file uploaded successfully")
}
)
public Map<String, String> uploadTranslations(
@FormDataParam("file") FormDataBodyPart file,
@QueryParam("language") String language,
Expand All @@ -83,8 +93,11 @@ public Map<String, String> uploadTranslations(
@GET
@Path("/settings/cover-page/templates")
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = "Settings")
@Operation(summary = "Get list of cover page predefined template names")
@Operation(summary = "Get list of cover page predefined template names",
responses = {
@ApiResponse(responseCode = "200", description = "Template names retrieved successfully")
}
)
public Collection<String> getCoverPageTemplateNames() {
if (predefinedCoverPageTemplates == null) {
predefinedCoverPageTemplates = new CoverPageSettings().getPredefinedTemplates();
Expand All @@ -94,8 +107,11 @@ public Collection<String> getCoverPageTemplateNames() {

@POST
@Path("/settings/cover-page/templates/{template}")
@Tag(name = "Settings")
@Operation(summary = "Persist content of cover page predefined template")
@Operation(summary = "Persist content of cover page predefined template",
responses = {
@ApiResponse(responseCode = "200", description = "Template persisted successfully")
}
)
public void persistCoverPageTemplate(@PathParam("template") String template, @QueryParam("scope") String scope) {
if (!getCoverPageTemplateNames().contains(template)) {
throw new NotFoundException(String.format("There's no predefined template with name '%s'", template));
Expand All @@ -114,8 +130,11 @@ public void persistCoverPageTemplate(@PathParam("template") String template, @Qu
@DELETE
@Path("/settings/cover-page/names/{name}/images")
@Produces(MediaType.APPLICATION_JSON)
@Tag(name = "Settings")
@Operation(summary = "Deletes images in SVN linked to specified cover page within specified scope (global or certain project)")
@Operation(summary = "Deletes images in SVN linked to specified cover page within specified scope (global or certain project)",
responses = {
@ApiResponse(responseCode = "200", description = "Images deleted successfully")
}
)
public void deleteImages(@PathParam("name") String coverPageName, @QueryParam("scope") @DefaultValue("") String scope) {
new CoverPageSettings().deleteCoverPageImages(coverPageName, scope);
}
Expand All @@ -124,7 +143,11 @@ public void deleteImages(@PathParam("name") String coverPageName, @QueryParam("s
@Path("/settings/style-package/suitable-names")
@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 a document",
responses = {
@ApiResponse(responseCode = "200", description = "Successfully retrieved the list of style package names")
}
)
public Collection<SettingName> getSuitableStylePackageNames(@QueryParam("projectId") String projectId, @QueryParam("spaceId") String spaceId, @QueryParam("documentName") String documentName) {
if (projectId == null || spaceId == null || documentName == null) {
throw new BadRequestException("Parameters 'projectId', 'spaceId', 'documentName' are required'");
Expand Down
Loading

0 comments on commit 9a89ff6

Please sign in to comment.