Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Extended REST API annotation #182

Merged
merged 2 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading