diff --git a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/DossierTemplateControllerV2.java b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/DossierTemplateControllerV2.java index 1d0946f4d..1376d1d60 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/DossierTemplateControllerV2.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/DossierTemplateControllerV2.java @@ -1,30 +1,166 @@ package com.iqser.red.persistence.service.v2.external.api.impl.controller; +import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_RULES; +import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_RULES; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import org.springframework.core.io.InputStreamResource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierTemplateController; +import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; +import com.iqser.red.service.persistence.management.v1.processor.service.RulesValidationService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils; +import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequest; +import com.iqser.red.service.persistence.service.v2.api.external.model.RulesValidationMessage; +import com.iqser.red.service.persistence.service.v2.api.external.model.RulesValidationResponse; import com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource; +import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation; +import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; + +import feign.FeignException; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; +import lombok.SneakyThrows; @RestController @RequiredArgsConstructor @Tag(name = "1. Dossier templates endpoints", description = "Provides operations related to dossier templates") public class DossierTemplateControllerV2 implements DossierTemplateResource { + private static final String RULES_DOWNLOAD_FILE_NAME_SUFFIX = "-rules.drl"; + private final DossierTemplateController dossierTemplateController; + private final RulesPersistenceService rulesPersistenceService; + private final RulesValidationService rulesValidationService; + private final AuditPersistenceService auditPersistenceService; + public List getAllDossierTemplates() { + return dossierTemplateController.getAllDossierTemplates(); } public DossierTemplateModel getDossierTemplate(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) { + return dossierTemplateController.getDossierTemplate(dossierTemplateId); } + @PreAuthorize("hasAuthority('" + WRITE_RULES + "')") + public ResponseEntity uploadEntityRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, + @Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file, + @Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false, defaultValue = "false") boolean dryRun) { + + return uploadRules(dossierTemplateId, RuleFileType.ENTITY, file, dryRun); + } + + + @PreAuthorize("hasAuthority('" + READ_RULES + "')") + public ResponseEntity downloadEntityRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) { + + return downloadRules(dossierTemplateId, RuleFileType.ENTITY); + } + + + @PreAuthorize("hasAuthority('" + WRITE_RULES + "')") + public ResponseEntity uploadComponentRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, + @Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file, + @Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false, defaultValue = "false") boolean dryRun) { + + return uploadRules(dossierTemplateId, RuleFileType.COMPONENT, file, dryRun); + } + + + @PreAuthorize("hasAuthority('" + READ_RULES + "')") + public ResponseEntity downloadComponentRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, + @PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType) { + + return downloadRules(dossierTemplateId, RuleFileType.COMPONENT); + } + + + @SneakyThrows + private ResponseEntity uploadRules(String dossierTemplateId, RuleFileType ruleFileType, MultipartFile file, boolean dryRun) { + + var rulesUploadRequest = RulesUploadRequest.builder() + .rules(new String(file.getBytes(), StandardCharsets.UTF_8)) + .dossierTemplateId(dossierTemplateId) + .ruleFileType(ruleFileType) + .build(); + try { + DroolsSyntaxValidation droolsSyntaxValidation = rulesValidationService.validateRules(rulesUploadRequest.getRuleFileType(), rulesUploadRequest.getRules()); + if (!droolsSyntaxValidation.isCompiled()) { + var rulesSyntaxErrorMessages = droolsSyntaxValidation.getDroolsSyntaxErrorMessages() + .stream() + .map(errorMessage -> RulesValidationMessage.builder() + .line(errorMessage.getLine()) + .column(errorMessage.getColumn()) + .message(errorMessage.getMessage()) + .build()) + .toList(); + + // TODO Add warning and deprecations to response + return new ResponseEntity<>(RulesValidationResponse.builder().errors(rulesSyntaxErrorMessages).build(), HttpStatus.UNPROCESSABLE_ENTITY); + } + } catch (FeignException e) { + if (e.status() == HttpStatus.BAD_REQUEST.value()) { + throw new BadRequestException("The provided rule string is not a valid drools rule file!"); + } + } + + if (!dryRun) { + rulesPersistenceService.setRules(rulesUploadRequest.getRules(), rulesUploadRequest.getDossierTemplateId(), rulesUploadRequest.getRuleFileType()); + } + + auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(rulesUploadRequest.getDossierTemplateId()) + .category(AuditCategory.DOSSIER_TEMPLATE.name()) + .message(String.format("%s Rules have been updated", rulesUploadRequest.getRuleFileType())) + .build()); + + // TODO Add warning and deprecations to response + return new ResponseEntity<>(RulesValidationResponse.builder().build(), HttpStatus.OK); + } + + + private ResponseEntity downloadRules(String dossierTemplateId, RuleFileType ruleFileType) { + + var ruleEntity = rulesPersistenceService.getRules(dossierTemplateId, ruleFileType); + + var data = ruleEntity.getValue().getBytes(StandardCharsets.UTF_8); + + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); + + httpHeaders.add("Content-Disposition", "attachment" + "; filename*=utf-8''" + StringEncodingUtils.urlEncode(ruleFileType.name().toLowerCase() + RULES_DOWNLOAD_FILE_NAME_SUFFIX)); + + InputStream is = new ByteArrayInputStream(data); + + return new ResponseEntity<>(new InputStreamResource(is), httpHeaders, HttpStatus.OK); + } + } diff --git a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/RulesDeprecationMessage.java b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/RulesDeprecationMessage.java new file mode 100644 index 000000000..c4f2f3681 --- /dev/null +++ b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/RulesDeprecationMessage.java @@ -0,0 +1,28 @@ +package com.iqser.red.service.persistence.service.v2.api.external.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +@Schema(description = "Show where deprecated methods are used in the rules file.") +public class RulesDeprecationMessage { + + @Schema(description = "The Line where the deprecated method is used.") + Integer line; + @Schema(description = "The Column where the deprecated method is used.") + Integer column; + @Schema(description = "The deprecated message, should point to method that should be used instead.") + String message; + @Schema(description = "The name of the deprecated method.") + String methodName; + +} diff --git a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/RulesValidationMessage.java b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/RulesValidationMessage.java new file mode 100644 index 000000000..6c78ba432 --- /dev/null +++ b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/RulesValidationMessage.java @@ -0,0 +1,26 @@ +package com.iqser.red.service.persistence.service.v2.api.external.model; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +@Schema(description = "Shows where to find problems in the uploaded rules file") +public class RulesValidationMessage { + + @Schema(description = "The Line where it occurred.") + Integer line; + @Schema(description = "The Column where it occurred.") + Integer column; + @Schema(description = "The error or warning message.") + String message; + +} diff --git a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/RulesValidationResponse.java b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/RulesValidationResponse.java new file mode 100644 index 000000000..e0fdd2eec --- /dev/null +++ b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/model/RulesValidationResponse.java @@ -0,0 +1,34 @@ +package com.iqser.red.service.persistence.service.v2.api.external.model; + +import java.util.ArrayList; +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +@Schema(description = "Object containing rules validation result") +public class RulesValidationResponse { + + @Builder.Default + @Schema(description = "Show where errors are in the uploaded rules file.") + List errors = new ArrayList<>(); + + /* + @Builder.Default + @Schema(description = "Show where warnings are in the uploaded rules file.") + List warnings = new ArrayList<>(); + @Builder.Default + @Schema(description = "Show deprecated methods are used in the uploaded rules file.") + List deprecationWarnings = new ArrayList<>(); +*/ +} diff --git a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/resource/DossierTemplateResource.java b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/resource/DossierTemplateResource.java index dd0f0e2a2..e2dbdb738 100644 --- a/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/resource/DossierTemplateResource.java +++ b/persistence-service-v1/persistence-service-external-api-v2/src/main/java/com/iqser/red/service/persistence/service/v2/api/external/resource/DossierTemplateResource.java @@ -1,14 +1,27 @@ package com.iqser.red.service.persistence.service.v2.api.external.resource; import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType; +import com.iqser.red.service.persistence.service.v2.api.external.model.RulesValidationResponse; + import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; + +import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -18,9 +31,16 @@ public interface DossierTemplateResource { String DOSSIER_TEMPLATE_PATH = "/dossier-templates"; String PATH = ExternalApiConstants.BASE_PATH + DOSSIER_TEMPLATE_PATH; + + String ENTITY_RULES_PATH = "/entity-rules"; + String COMPONENT_RULES_PATH = "/component-rules"; String DOSSIER_TEMPLATE_ID_PARAM = "dossierTemplateId"; String DOSSIER_TEMPLATE_ID_PATH_VARIABLE = "/{" + DOSSIER_TEMPLATE_ID_PARAM + "}"; + String RULE_FILE_TYPE_PARAMETER_NAME = "ruleFileType"; + + String DRY_RUN_PARAM = "dryRun"; + @GetMapping(value = PATH, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Lists all existing DossierTemplates.", description = "None") @@ -34,5 +54,37 @@ public interface DossierTemplateResource { DossierTemplateModel getDossierTemplate(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId); + @ResponseStatus(value = HttpStatus.NO_CONTENT) + @PostMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + ENTITY_RULES_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Upload a component or entity rules file in drools format for a specific DossierTemplate.") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful."), @ApiResponse(responseCode = "400", description = "Uploaded rules could not be verified.")}) + ResponseEntity uploadEntityRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, + @Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file, + @Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false ,defaultValue = "false") boolean dryRun); + + @ResponseBody + @ResponseStatus(value = HttpStatus.OK) + @Operation(summary = "Returns file containing the currently used Drools rules.") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) + @GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + ENTITY_RULES_PATH, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + ResponseEntity downloadEntityRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId); + + + + @ResponseStatus(value = HttpStatus.NO_CONTENT) + @PostMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_RULES_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Upload a component or entity rules file in drools format for a specific DossierTemplate.") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Rules upload successful."), @ApiResponse(responseCode = "400", description = "Uploaded rules could not be verified.")}) + ResponseEntity uploadComponentRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, + @Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file, + @Parameter(name = DRY_RUN_PARAM, description = "If true rules will be only validated not stored.") @RequestParam(value = DRY_RUN_PARAM, required = false ,defaultValue = "false") boolean dryRun); + + @ResponseBody + @ResponseStatus(value = HttpStatus.OK) + @Operation(summary = "Returns file containing the currently used Drools rules.") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) + @GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_RULES_PATH, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + ResponseEntity downloadComponentRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType); + } diff --git a/persistence-service-v1/persistence-service-external-api-v2/src/main/resources/api/openapi.yaml b/persistence-service-v1/persistence-service-external-api-v2/src/main/resources/api/openapi.yaml index a4b42ba64..b13f5f3f5 100644 --- a/persistence-service-v1/persistence-service-external-api-v2/src/main/resources/api/openapi.yaml +++ b/persistence-service-v1/persistence-service-external-api-v2/src/main/resources/api/openapi.yaml @@ -108,6 +108,170 @@ paths: $ref: '#/components/responses/429' "500": $ref: '#/components/responses/500' + /api/dossier-templates/{dossierTemplateId}/entity-rules: + get: + operationId: downloadEntityRules + tags: + - 1. Dossier Templates + summary: Download the entity rules of a specific dossier template. + description: | + Utilize this endpoint to download the entity rules of a designated dossier template. The file is named 'entity-rules.drl' + and contains the set of rules to annotate the entities in an analyzed file. The content of this file is in the Drools Rule Language + (DRL) format. Please find more details about the DRL in the + [Drools Language Reference](https://docs.drools.org/8.44.0.Final/drools-docs/drools/language-reference/index.html). + parameters: + - $ref: '#/components/parameters/dossierTemplateId' + responses: + "200": + headers: + Content-Disposition: + schema: + type: string + example: attachment; filename*=utf-8''entity-rules.drl + content: + application/octet-stream: + schema: + type: string + format: binary + description: | + Successfully downloaded the requested rules file. + "400": + $ref: '#/components/responses/400' + "401": + $ref: '#/components/responses/401' + "403": + $ref: '#/components/responses/403' + "404": + $ref: '#/components/responses/404-dossier-template' + "429": + $ref: '#/components/responses/429' + "500": + $ref: '#/components/responses/500' + post: + operationId: uploadEntityRules + tags: + - 1. Dossier Templates + summary: Upload or validate a entity rules file for a specific dossier template. + description: | + Utilize this endpoint to upload the entity rules to a designated dossier template. With the 'dryRun' parameter, + you have the possibility to just validate the rules file without actually saving it in the dossier template. + + The uploaded rule file will be saved only if 'dryRun' is set to `false` and the response code is `200`. In this + case, the response object does not contain errors. + parameters: + - $ref: '#/components/parameters/dossierTemplateId' + - $ref: '#/components/parameters/dryRun' + requestBody: + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/UploadRequest' + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/RuleValidation' + example: + errors: [ ] + description: | + Successfully uploaded or validated the entity rules file. The returned response object will not contain any errors. + "400": + $ref: '#/components/responses/400' + "401": + $ref: '#/components/responses/401' + "403": + $ref: '#/components/responses/403' + "404": + $ref: '#/components/responses/404-dossier' + "422": + $ref: '#/components/responses/422-rules' + "429": + $ref: '#/components/responses/429' + "500": + $ref: '#/components/responses/500' + /api/dossier-templates/{dossierTemplateId}/component-rules: + get: + operationId: downloadComponentRules + tags: + - 1. Dossier Templates + summary: Download the component rules of a specific dossier template. + description: | + Utilize this endpoint to download the component rules of a designated dossier template. The file is named 'component-rules.drl' + and contains the set of rules to build components based on entities of an analyzed file. The content of this file is in the Drools Rule Language + (DRL) format. Please find more details about the DRL in the + [Drools Language Reference](https://docs.drools.org/8.44.0.Final/drools-docs/drools/language-reference/index.html). + parameters: + - $ref: '#/components/parameters/dossierTemplateId' + responses: + "200": + headers: + Content-Disposition: + schema: + type: string + example: attachment; filename*=utf-8''component-rules.drl + content: + application/octet-stream: + schema: + type: string + format: binary + description: | + Successfully downloaded the requested rules file. + "400": + $ref: '#/components/responses/400' + "401": + $ref: '#/components/responses/401' + "403": + $ref: '#/components/responses/403' + "404": + $ref: '#/components/responses/404-dossier-template' + "429": + $ref: '#/components/responses/429' + "500": + $ref: '#/components/responses/500' + post: + operationId: uploadComponentRules + tags: + - 1. Dossier Templates + summary: Upload or validate a component rules file for a specific dossier template. + description: | + Utilize this endpoint to upload the component rules to a designated dossier template. With the 'dryRun' parameter, + you have the possibility to just validate the rules file without actually saving it in the dossier template. + + The uploaded rule file will be saved only if 'dryRun' is set to `false` and the response code is `200`. In this + case, the response object does not contain errors. + parameters: + - $ref: '#/components/parameters/dossierTemplateId' + - $ref: '#/components/parameters/dryRun' + requestBody: + content: + multipart/form-data: + schema: + $ref: '#/components/schemas/UploadRequest' + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/RuleValidation' + example: + errors: [ ] + description: | + Successfully uploaded or validated the component rules file. The returned response object will not contain any errors. + "400": + $ref: '#/components/responses/400' + "401": + $ref: '#/components/responses/401' + "403": + $ref: '#/components/responses/403' + "404": + $ref: '#/components/responses/404-dossier' + "422": + $ref: '#/components/responses/422-rules' + "429": + $ref: '#/components/responses/429' + "500": + $ref: '#/components/responses/500' /api/dossier-templates/{dossierTemplateId}/dossiers: get: operationId: getDossiers @@ -664,6 +828,13 @@ components: $ref: '#/components/schemas/ErrorMessage' description: | Name conflict: The provided name is already in use by another dossier. It needs to be unique in the scope of your workspace. + 422-rules: + content: + '*/*': + schema: + $ref: '#/components/schemas/RuleValidation' + description: | + Invalid rules file: There were validation errors, the rules file is unprocessable. "429": content: '*/*': @@ -687,6 +858,18 @@ components: style: simple explode: false description: The identifier of a dossier template + dryRun: + name: dryRun + in: query + required: false + schema: + default: false + type: boolean + style: form + explode: true + description: | + A toggle to activate the dry-run mode: If set to `false` (default), the request will update the system. + If set to `true`, the request will just be evaluated without actual changes in the system. dossierId: name: dossierId in: path @@ -1681,7 +1864,7 @@ components: description: A detailed description of the error, providing insights on the problem and potentially how to resolve or avoid it. example: timestamp: "2023-09-21T12:45:00Z" - message: "Invalid input provided for the 'name' field." + message: "An error occurred while processing the request." FileAttributes: type: object description: Additional file attributes that can be set or imported @@ -2202,6 +2385,43 @@ components: type: string type: array type: object + RuleValidationMessage: + description: Object containing information about an uploaded rules file. + example: + line: 123 + column: 45 + message: "Unable to Analyse Expression ..." + properties: + line: + description: The line number where the error or warning occurs. + format: int32 + type: integer + column: + description: The column number where the error or warning occurs. + format: int32 + type: integer + message: + description: The error or warning message that describes the details. + type: string + type: object + RuleValidation: + description: | + Information about the uploaded rules file. The `error` field is empty if there were no validation errors in the uploaded rules file. + example: + errors: + - line: 123 + column: 45 + message: "Unable to Analyse Expression ..." + - line: 234 + column: 5 + message: "Invalid rule syntax ..." + properties: + errors: + description: List of errors found in the uploaded rules file. + items: + $ref: '#/components/schemas/RuleValidationMessage' + type: array + type: object LicenseReport: type: object description: A comprehensive report of licensing metrics and usage statistics.