Merge branch 'RED-7962' into 'master'

RED-7962 Added 'red-experimental' role to restrict usage of experimental...

Closes RED-7962

See merge request redactmanager/persistence-service!227
This commit is contained in:
Kilian Schüttler 2023-11-27 18:40:10 +01:00
commit 5eb4d86808
6 changed files with 227 additions and 3 deletions

View File

@ -1,5 +1,7 @@
package com.iqser.red.persistence.service.v2.external.api.impl.controller;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.EXPERIMENTAL;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_FILE_ATTRIBUTES_CONFIG;
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;
@ -21,6 +23,7 @@ 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.persistence.service.v1.external.api.impl.controller.FileAttributesController;
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;
@ -31,6 +34,8 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemp
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.FileAttributeDefinition;
import com.iqser.red.service.persistence.service.v2.api.external.model.FileAttributeDefinitionList;
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;
@ -55,6 +60,7 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
private final RulesPersistenceService rulesPersistenceService;
private final RulesValidationService rulesValidationService;
private final AuditPersistenceService auditPersistenceService;
private final FileAttributesController fileAttributesController;
public List<DossierTemplateModel> getAllDossierTemplates() {
@ -69,7 +75,7 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
}
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
@PreAuthorize("hasAuthority('" + WRITE_RULES + "') and hasAuthority('" + EXPERIMENTAL + "')")
public ResponseEntity<RulesValidationResponse> 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) {
@ -85,7 +91,7 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
}
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
@PreAuthorize("hasAuthority('" + WRITE_RULES + "') and hasAuthority('" + EXPERIMENTAL + "')")
public ResponseEntity<RulesValidationResponse> 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) {
@ -101,6 +107,27 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
return downloadRules(dossierTemplateId, RuleFileType.COMPONENT);
}
@PreAuthorize("hasAuthority('" + READ_FILE_ATTRIBUTES_CONFIG + "')")
public FileAttributeDefinitionList getFileAttributeDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
var fileAttributeConfigs = fileAttributesController.getFileAttributesConfiguration(dossierTemplateId);
return new FileAttributeDefinitionList(fileAttributeConfigs.getFileAttributeConfigs().stream()
.map(fileAttributeConfig -> FileAttributeDefinition.builder()
.id(fileAttributeConfig.getId())
.name(fileAttributeConfig.getLabel())
.type(fileAttributeConfig.getType())
.mappedCsvColumnHeader(fileAttributeConfig.getCsvColumnHeader())
.reportingPlaceholder(fileAttributeConfig.getPlaceholder())
.displaySettings(FileAttributeDefinition.DisplaySettings.builder()
.primaryAttribute(fileAttributeConfig.isPrimaryAttribute())
.editable(fileAttributeConfig.isEditable())
.filterable(fileAttributeConfig.isFilterable())
.displayedInFileList(fileAttributeConfig.isDisplayedInFileList())
.build())
.build())
.toList());
}
@SneakyThrows
private ResponseEntity<RulesValidationResponse> uploadRules(String dossierTemplateId, RuleFileType ruleFileType, MultipartFile file, boolean dryRun) {

View File

@ -0,0 +1,34 @@
package com.iqser.red.service.persistence.service.v2.api.external.model;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileAttributeType;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class FileAttributeDefinition {
private String id;
private String name;
private FileAttributeType type = FileAttributeType.TEXT;
private String mappedCsvColumnHeader;
private String reportingPlaceholder;
private DisplaySettings displaySettings;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class DisplaySettings {
private boolean primaryAttribute;
private boolean editable;
private boolean filterable;
private boolean displayedInFileList;
}
}

View File

@ -0,0 +1,19 @@
package com.iqser.red.service.persistence.service.v2.api.external.model;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FileAttributeDefinitionList {
@Builder.Default
private List<FileAttributeDefinition> fileAttributeDefinitions = new ArrayList<>();
}

View File

@ -2,6 +2,7 @@ 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.FileAttributeDefinitionList;
import com.iqser.red.service.persistence.service.v2.api.external.model.RulesValidationResponse;
import io.swagger.v3.oas.annotations.Operation;
@ -34,6 +35,8 @@ public interface DossierTemplateResource {
String ENTITY_RULES_PATH = "/entity-rules";
String COMPONENT_RULES_PATH = "/component-rules";
String FILE_ATTRIBUTE_DEFINITIONS_PATH = "/file-attribute-definitions";
String DOSSIER_TEMPLATE_ID_PARAM = "dossierTemplateId";
String DOSSIER_TEMPLATE_ID_PATH_VARIABLE = "/{" + DOSSIER_TEMPLATE_ID_PARAM + "}";
@ -86,5 +89,8 @@ public interface DossierTemplateResource {
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_RULES_PATH, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
ResponseEntity<InputStreamResource> downloadComponentRules(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType);
@Operation(summary = "Get the file attribute definitions of a DossierTemplate.", description = "None")
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + FILE_ATTRIBUTE_DEFINITIONS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "File attribute definitions returned successfully."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
FileAttributeDefinitionList getFileAttributeDefinitions(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);
}

View File

@ -272,6 +272,26 @@ paths:
$ref: '#/components/responses/429'
"500":
$ref: '#/components/responses/500'
/api/dossier-templates/{dossierTemplateId}/file-attribute-definitions:
get:
summary: Returns the list of all existing file attribute definitions
tags:
- 1. Dossier Templates
description: |
Retrieves a collection of file attribute definitions associated with a specific dossier template. Each file
attribute definition includes details such as attribute type, name, and other relevant metadata. This endpoint
is useful for clients needing to understand what attributes are expected or allowed for files under a particular
dossier template.
parameters:
- $ref: '#/components/parameters/dossierTemplateId'
responses:
"200":
content:
'*/*':
schema:
$ref: '#/components/schemas/FileAttributeDefinitionList'
description: |
Successfully returned the file attribute definitions for the specified dossier template.
/api/dossier-templates/{dossierTemplateId}/dossiers:
get:
operationId: getDossiers
@ -1377,6 +1397,120 @@ components:
entityRuleId: DEF.13.37
type: another_entity_type
page: 456
FileAttributeDefinition:
type: object
description: |
The `FileAttributeDefinition` object contains the relevant information to define a file attribute. File attributes
are used to manage additional meta-data of files.
properties:
id:
type: string
format: uuid
description: |
A unique identifier for the file attribute definition. This ID is automatically generated by
the system upon creation and is used for referencing the file attribute definition in API calls.
name:
type: string
description: |
User-defined name of the file attribute definition, capturing its essence. The name needs to be unique
for the dossier template.
type:
type: string
enum:
- TEXT
- NUMBER
- DATE
description: |
Determines the type of the dossier attribute's value. Please note that currently the system
does not validate the values against this definition. This is just a hint for a user interface
that needs to handle invalid entries. Possible values for the type:
- `TEXT`: The value is just a string, i.e., any sequence of characters.
- `NUMBER`: The value is a string expressing a number, with or without decimals.
- `DATE`: The value is a string expressing a date information.
mappedCsvColumnHeader:
type: string
description: |
The name of a CSV column. When importing a CSV file with additional file information the system gets the value from the respective CSV column.
reportingPlaceholder:
type: string
description: |
The name of the placeholder of the file attribute that can be used in report templates. The placeholder follows a specific format convention:
`{{file.attribute.<name>}}` while the name transformed into 'PascalCase' and does not contain whitespaces. The placeholder is unique in a dossier template.
displaySettings:
$ref: '#/components/schemas/FileAttributeDisplaySettings'
required:
- name
- type
example:
id: "123e4567-e89b-12d3-a456-426614174000"
name: "Document Type"
type: "TEXT"
mappedCsvColumnHeader: "DocumentCategory"
reportingPlaceholder: "{{file.attribute.DocumentType}}"
displaySettings:
primaryAttribute: true
editable: true
filterable: true
displayedInFileList: false
FileAttributeDisplaySettings:
type: object
description: |
Display setting for the RedactManager and DocuMine user interface. These settings control how the UI handles and presents the file attributes.
properties:
primaryAttribute:
type: boolean
description: |
If true, the RedactManager and DocuMine user interfaces show the value of the file attribute in the file list below the file name.
editable:
type: boolean
description: |
If true, the RedactManager and DocuMine user interfaces allow manual editing of the value. Otherwise only importing and setting by rules would be possible.
filterable:
type: boolean
description: |
If true, the RedactManager and DocuMine user interfaces add filter options to the file list.
displayedInFileList:
type: boolean
description: |
if true, the RedactManager and DocuMine user interfaces show the values in the file list.
required:
- primaryAttribute
- editable
- filterable
- displayedInFileList
example: :
primaryAttribute: false
editable: true
filterable: true
displayedInFileList: false
FileAttributeDefinitionList:
type: object
description: A list of file attribute definitions.
properties:
fileAttributeDefinitions:
items:
$ref: '#/components/schemas/FileAttributeDefinition'
type: array
example:
- id: "123e4567-e89b-12d3-a456-426614174000"
name: "Document Type"
type: "TEXT"
mappedCsvColumnHeader: "DocumentCategory"
reportingPlaceholder: "{{file.attribute.DocumentType}}"
displaySettings:
primaryAttribute: true
editable: true
filterable: true
displayedInFileList: false
- id: "23e45678-e90b-12d3-a456-765114174321"
name: "Comment"
type: "TEXT"
reportingPlaceholder: "{{file.attribute.Comment}}"
displaySettings:
primaryAttribute: false
editable: true
filterable: false
displayedInFileList: false
Dossier:
type: object
description: |
@ -1385,6 +1519,7 @@ components:
properties:
id:
type: string
format: uuid
description: |
A unique identifier for the dossier. This ID is automatically generated by
the system upon creation and is used for referencing the dossier in API calls.

View File

@ -2,6 +2,9 @@ package com.iqser.red.service.persistence.management.v1.processor.roles;
public final class ActionRoles {
// Experimental
public static final String EXPERIMENTAL = "red-experimental";
// Audit
public static final String SEARCH_AUDIT_LOG = "red-search-audit-log";