RED-8670: integrate table inference from research

This commit is contained in:
Kilian Schuettler 2024-05-17 00:39:55 +02:00
parent 682af154f4
commit 9e2a603fc9
15 changed files with 446 additions and 397 deletions

View File

@ -1,25 +1,45 @@
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 static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierResource.DOSSIER_ID_PARAM;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource.DOSSIER_TEMPLATE_ID_PARAM;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource.FILE_ID_PARAM;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
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.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierTemplateController;
import com.google.common.base.Strings;
import com.iqser.red.persistence.service.v1.external.api.impl.controller.StatusController;
import com.iqser.red.persistence.service.v2.external.api.impl.mapper.ComponentMappingMapper;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.model.ComponentMappingDownloadModel;
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentLogService;
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentMappingService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntityReference;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue;
import com.iqser.red.service.persistence.service.v2.api.external.model.Component;
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingMetadataModel;
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingSummary;
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentValue;
import com.iqser.red.service.persistence.service.v2.api.external.model.EntityReference;
import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponents;
@ -29,6 +49,7 @@ import com.iqser.red.service.persistence.service.v2.api.external.resource.Compon
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.experimental.FieldDefaults;
@RestController
@ -37,10 +58,12 @@ import lombok.experimental.FieldDefaults;
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class ComponentControllerV2 implements ComponentResource {
DossierTemplateController dossierTemplateController;
ComponentLogService componentLogService;
StatusController statusController;
FileStatusService fileStatusService;
ComponentMappingService componentMappingService;
ComponentMappingMapper componentMappingMapper = ComponentMappingMapper.INSTANCE;
DossierTemplatePersistenceService dossierTemplatePersistenceService;
@Override
@ -49,7 +72,7 @@ public class ComponentControllerV2 implements ComponentResource {
@PathVariable(FILE_ID_PARAM) String fileId,
@RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails) {
dossierTemplateController.getDossierTemplate(dossierTemplateId);
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
var componentLog = componentLogService.getComponentLog(dossierId, fileId, true);
Map<String, List<String>> basicComponent = new LinkedHashMap<>();
@ -119,11 +142,109 @@ public class ComponentControllerV2 implements ComponentResource {
@PathVariable(DOSSIER_ID_PARAM) String dossierId,
@RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails) {
dossierTemplateController.getDossierTemplate(dossierTemplateId);
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
var dossierFiles = statusController.getDossierStatus(dossierId);
return new FileComponentsList(dossierFiles.stream()
.map(file -> getComponents(dossierTemplateId, dossierId, file.getFileId(), includeDetails))
.toList());
}
@Override
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
public ComponentMappingSummary getComponentMappingSummaries(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
List<com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata> summaries = componentMappingService.getMetaDataByDossierTemplateId(dossierTemplateId);
List<ComponentMappingMetadataModel> componentMappingMetadataModelList = componentMappingMapper.toModelList(summaries);
return new ComponentMappingSummary(dossierTemplateId, componentMappingMetadataModelList);
}
@Override
@SneakyThrows
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
public ComponentMappingMetadataModel uploadMapping(String dossierTemplateId, MultipartFile file, String name, String encoding, char delimiter) {
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
String nameToUse = Strings.isNullOrEmpty(name) ? file.getName().split("\\.")[0] : name;
if (Strings.isNullOrEmpty(nameToUse)) {
throw new BadRequestException("The provided file name is not valid!");
}
Path mappingFile = saveToFile(file);
String fileName = file.getOriginalFilename() == null ? nameToUse + ".csv" : file.getOriginalFilename();
com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata metaData = componentMappingService.create(dossierTemplateId, nameToUse, fileName, delimiter, encoding, mappingFile.toFile());
Files.deleteIfExists(mappingFile);
return componentMappingMapper.toModel(metaData);
}
@Override
@SneakyThrows
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
public ComponentMappingMetadataModel updateMapping(String dossierTemplateId, String componentMappingId, MultipartFile file, String encoding, char delimiter) {
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
Path mappingFile = saveToFile(file);
com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata resultMetaData = componentMappingService.update(componentMappingId, encoding, delimiter, mappingFile.toFile());
Files.deleteIfExists(mappingFile);
return componentMappingMapper.toModel(resultMetaData);
}
@Override
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
public ResponseEntity<?> downloadMapping(String dossierTemplateId, String componentMappingId) {
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
ComponentMappingDownloadModel mappingDownloadModel = componentMappingService.getMappingForDownload(componentMappingId);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.TEXT_PLAIN);
httpHeaders.add("Content-Disposition",
"attachment"
+ "; filename*="
+ mappingDownloadModel.encoding().toLowerCase(Locale.US)
+ "''"
+ StringEncodingUtils.urlEncode(mappingDownloadModel.fileName()));
return new ResponseEntity<>(mappingDownloadModel.mappingFileResource(), httpHeaders, HttpStatus.OK);
}
@Override
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
public ResponseEntity<?> deleteMapping(String dossierTemplateId, String componentMappingId) {
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
componentMappingService.delete(componentMappingId);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@SneakyThrows
private static Path saveToFile(MultipartFile file) {
Path mappingFile = Files.createTempFile(file.getName(), ".csv");
try (var out = new FileOutputStream(mappingFile.toFile())) {
out.write(file.getBytes());
}
return mappingFile;
}
}

View File

@ -6,16 +6,11 @@ import static com.iqser.red.service.persistence.management.v1.processor.roles.Ac
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_RULES;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Locale;
import org.mapstruct.factory.Mappers;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@ -28,14 +23,10 @@ import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.google.common.base.Strings;
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.persistence.service.v2.external.api.impl.mapper.ComponentMappingMapper;
import com.iqser.red.service.persistence.management.v1.processor.model.ComponentMappingDownloadModel;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.RuleSetEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentMappingService;
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;
@ -45,11 +36,8 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCatego
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.component.ComponentMappingMetaData;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.DroolsValidationResponse;
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.ComponentMappingSummaries;
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingSummary;
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.resource.DossierTemplateResource;
@ -74,8 +62,7 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
private final RulesValidationService rulesValidationService;
private final AuditPersistenceService auditPersistenceService;
private final FileAttributesController fileAttributesController;
private final ComponentMappingService componentMappingService;
private final ComponentMappingMapper componentMappingMapper = ComponentMappingMapper.INSTANCE;
public List<DossierTemplateModel> getAllDossierTemplates() {
@ -225,86 +212,4 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
return new ResponseEntity<>(new InputStreamResource(is), httpHeaders, HttpStatus.OK);
}
@Override
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
public ComponentMappingSummaries getComponentMappingSummaries(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId) {
List<ComponentMappingMetaData> summaries = componentMappingService.getMetaDataByDossierTemplateId(dossierTemplateId);
List<ComponentMappingSummary> componentMappingSummaryList = componentMappingMapper.toComponentMappingSummaryList(summaries);
return new ComponentMappingSummaries(dossierTemplateId, componentMappingSummaryList);
}
@Override
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
public ComponentMappingSummary uploadMapping(String dossierTemplateId, MultipartFile file, String name, String encoding, char delimiter) {
String nameToUse = Strings.isNullOrEmpty(name) ? file.getName().split("\\.")[0] : name;
if (Strings.isNullOrEmpty(nameToUse)) {
throw new BadRequestException("The provided file name is not valid!");
}
File mappingFile = saveToFile(file);
String fileName = file.getOriginalFilename() == null ? nameToUse + ".csv" : file.getOriginalFilename();
ComponentMappingMetaData metaData = componentMappingService.create(dossierTemplateId, nameToUse, fileName , delimiter, encoding, mappingFile);
return componentMappingMapper.toComponentMappingSummary(metaData);
}
@Override
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
public ComponentMappingSummary updateMapping(String dossierTemplateId, String componentMappingId, MultipartFile file, String encoding, char delimiter) {
File mappingFile = saveToFile(file);
ComponentMappingMetaData resultMetaData = componentMappingService.update(componentMappingId, encoding, delimiter, mappingFile);
return componentMappingMapper.toComponentMappingSummary(resultMetaData);
}
@Override
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
public ResponseEntity<?> downloadMapping(String dossierTemplateId, String componentMappingId) {
ComponentMappingDownloadModel mappingDownloadModel = componentMappingService.getMappingForDownload(componentMappingId);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.TEXT_PLAIN);
httpHeaders.add("Content-Disposition",
"attachment"
+ "; filename*="
+ mappingDownloadModel.encoding().toLowerCase(Locale.US)
+ "''"
+ StringEncodingUtils.urlEncode(mappingDownloadModel.fileName()));
return new ResponseEntity<>(mappingDownloadModel.mappingFileResource(), httpHeaders, HttpStatus.OK);
}
@Override
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
public ResponseEntity<?> deleteMapping(String dossierTemplateId, String componentMappingId) {
componentMappingService.delete(componentMappingId);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
@SneakyThrows
private static File saveToFile(MultipartFile file) {
Path mappingFile = Files.createTempFile(file.getName(), ".csv");
try (var out = new FileOutputStream(mappingFile.toFile())) {
out.write(file.getBytes());
}
return mappingFile.toFile();
}
}

View File

@ -5,8 +5,8 @@ import java.util.List;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetaData;
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingSummary;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata;
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingMetadataModel;
@Mapper
public interface ComponentMappingMapper {
@ -14,15 +14,15 @@ public interface ComponentMappingMapper {
ComponentMappingMapper INSTANCE = Mappers.getMapper(ComponentMappingMapper.class);
ComponentMappingSummary toComponentMappingSummary(ComponentMappingMetaData componentMappingMetaData);
ComponentMappingMetadataModel toModel(ComponentMappingMetadata componentMappingMetadata);
List<ComponentMappingSummary> toComponentMappingSummaryList(List<ComponentMappingMetaData> componentMappingMetaData);
List<ComponentMappingMetadataModel> toModelList(List<ComponentMappingMetadata> componentMappingMetadata);
ComponentMappingMetaData toComponentMappingMetaData(ComponentMappingSummary componentMappingSummary);
ComponentMappingMetadata toDto(ComponentMappingMetadataModel componentMappingMetadataModel);
List<ComponentMappingMetaData> toComponentMappingMetaDataList(List<ComponentMappingSummary> componentMappingSummary);
List<ComponentMappingMetadata> toDtoList(List<ComponentMappingMetadataModel> componentMappingMetadataModels);
}

View File

@ -14,9 +14,15 @@ import lombok.experimental.FieldDefaults;
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ComponentMappingSummaries {
public class ComponentMappingMetadataModel {
String dossierTemplateId;
List<ComponentMappingSummary> componentMappingSummaries;
String id;
String name;
String fileName;
Integer version;
List<String> columnLabels;
Integer numberOfLines;
String encoding;
char delimiter;
}

View File

@ -1,10 +1,7 @@
package com.iqser.red.service.persistence.service.v2.api.external.model;
import java.nio.charset.StandardCharsets;
import java.util.List;
import org.springframework.cglib.core.Local;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -19,13 +16,7 @@ import lombok.experimental.FieldDefaults;
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ComponentMappingSummary {
String id;
String name;
String fileName;
Integer version;
List<String> columnLabels;
Integer numberOfLines;
String encoding;
char delimiter;
String dossierTemplateId;
List<ComponentMappingMetadataModel> componentMappingMetadata;
}

View File

@ -8,20 +8,29 @@ import static com.iqser.red.service.persistence.service.v2.api.external.resource
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource.DOSSIER_TEMPLATE_PATH;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource.FILE_ID_PARAM;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource.FILE_ID_PATH_VARIABLE;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource.FILE_PATH;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
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.PutMapping;
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 com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingMetadataModel;
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingSummary;
import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponents;
import com.iqser.red.service.persistence.service.v2.api.external.model.FileComponentsList;
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;
@ -29,7 +38,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
@ResponseStatus(value = HttpStatus.OK)
public interface ComponentResource {
String PATH = ExternalApiConstants.BASE_PATH + DOSSIER_TEMPLATE_PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + DOSSIER_PATH + DOSSIER_ID_PATH_PARAM + FILE_PATH;
String PATH = ExternalApiConstants.BASE_PATH + DOSSIER_TEMPLATE_PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE;
String FILE_PATH = PATH + DOSSIER_PATH + DOSSIER_ID_PATH_PARAM + FileResource.FILE_PATH;
String COMPONENTS_PATH = "/components";
@ -44,8 +54,17 @@ public interface ComponentResource {
- false (default): The component object does not contain a field componentDetails.
""";
String COMPONENT_MAPPINGS_PATH = COMPONENTS_PATH + "/mappings";
String COMPONENT_MAPPING_ID_PARAM = "componentMappingId";
String COMPONENT_MAPPING_ID_PATH_VARIABLE = "/{" + COMPONENT_MAPPING_ID_PARAM + "}";
@GetMapping(value = PATH + FILE_ID_PATH_VARIABLE + COMPONENTS_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
String RULE_FILE_TYPE_PARAMETER_NAME = "ruleFileType";
String ENCODING_PARAM = "encoding";
String DELIMITER_PARAM = "delimiter";
String MAPPING_NAME_PARAM = "name";
@GetMapping(value = FILE_PATH + FILE_ID_PATH_VARIABLE + COMPONENTS_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
@Operation(summary = "Returns the components for a file", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
FileComponents getComponents(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
@ -54,11 +73,58 @@ public interface ComponentResource {
@Parameter(name = INCLUDE_DETAILS_PARAM, description = INCLUDE_DETAILS_DESCRIPTION) @RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails);
@GetMapping(value = PATH + BULK_COMPONENTS_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
@GetMapping(value = FILE_PATH + BULK_COMPONENTS_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
@Operation(summary = "Returns the components for all files of a dossier", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
FileComponentsList getComponentsOfDossier(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
@Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
@Parameter(name = INCLUDE_DETAILS_PARAM, description = INCLUDE_DETAILS_DESCRIPTION) @RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails);
@Operation(summary = "Get the component mapping summaries of a DossierTemplate.", description = "None")
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_MAPPINGS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Component mapping views returned successfully."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
ComponentMappingSummary getComponentMappingSummaries(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);
@Operation(summary = "Upload a new component mapping to a DossierTemplate.", description = "None")
@PostMapping(value = PATH
+ DOSSIER_TEMPLATE_ID_PATH_VARIABLE
+ COMPONENT_MAPPINGS_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Component mapping uploaded successfully."), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified mapping is not found.")})
ComponentMappingMetadataModel uploadMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
@Parameter(name = MAPPING_NAME_PARAM, description = "String of what the mapping should be accessible under. If left empty, the name of the file without the ending will be used as name.") @RequestParam(value = MAPPING_NAME_PARAM, required = false, defaultValue = "") String name,
@Parameter(name = ENCODING_PARAM, description = "The encoding of the file. Default is UTF-8.") @RequestParam(value = ENCODING_PARAM, required = false, defaultValue = "UTF-8") String encoding,
@Parameter(name = DELIMITER_PARAM, description = "The delimiter used in the file. Default is ','") @RequestParam(value = DELIMITER_PARAM, required = false, defaultValue = ",") char delimiter);
@Operation(summary = "Update an existing component mapping of a DossierTemplate.", description = "None")
@PutMapping(value = PATH
+ DOSSIER_TEMPLATE_ID_PATH_VARIABLE
+ COMPONENT_MAPPINGS_PATH
+ COMPONENT_MAPPING_ID_PATH_VARIABLE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Component mapping updated successfully."), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified mapping is not found.")})
ComponentMappingMetadataModel updateMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
@PathVariable(COMPONENT_MAPPING_ID_PARAM) String componentMappingId,
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
@Parameter(name = ENCODING_PARAM, description = "The encoding of the file. Default is UTF-8.") @RequestParam(value = ENCODING_PARAM, required = false, defaultValue = "UTF-8") String encoding,
@Parameter(name = DELIMITER_PARAM, description = "The delimiter used in the file. Default is ','") @RequestParam(value = DELIMITER_PARAM, required = false, defaultValue = ",") char delimiter);
@ResponseBody
@ResponseStatus(value = HttpStatus.OK)
@Operation(summary = "Returns file containing the specified mapping as a file.")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_MAPPINGS_PATH + COMPONENT_MAPPING_ID_PATH_VARIABLE, produces = MediaType.MULTIPART_FORM_DATA_VALUE)
ResponseEntity<?> downloadMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @PathVariable(COMPONENT_MAPPING_ID_PARAM) String componentMappingId);
@ResponseBody
@ResponseStatus(value = HttpStatus.OK)
@Operation(summary = "Deletes a specified mapping.")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified mapping is not found.")})
@DeleteMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_MAPPINGS_PATH + COMPONENT_MAPPING_ID_PATH_VARIABLE, produces = MediaType.MULTIPART_FORM_DATA_VALUE)
ResponseEntity<?> deleteMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @PathVariable(COMPONENT_MAPPING_ID_PARAM) String componentMappingId);
}

View File

@ -2,8 +2,6 @@ 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.dossiertemplate.rules.DroolsValidationResponse;
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingSummaries;
import com.iqser.red.service.persistence.service.v2.api.external.model.ComponentMappingSummary;
import com.iqser.red.service.persistence.service.v2.api.external.model.FileAttributeDefinitionList;
import io.swagger.v3.oas.annotations.Operation;
@ -15,11 +13,9 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
@ -38,20 +34,15 @@ public interface DossierTemplateResource {
String ENTITY_RULES_PATH = "/entity-rules";
String COMPONENT_RULES_PATH = "/component-rules";
String COMPONENT_MAPPINGS_PATH = "/component-mappings";
String COMPONENT_MAPPING_ID_PARAM = "componentMappingId";
String COMPONENT_MAPPING_ID_PATH_VARIABLE = "/{" + COMPONENT_MAPPING_ID_PARAM + "}";
String FILE_ATTRIBUTE_DEFINITIONS_PATH = "/file-attribute-definitions";
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";
String ENCODING_PARAM = "encoding";
String DELIMITER_PARAM = "delimiter";
String MAPPING_NAME_PARAM = "name";
@GetMapping(value = PATH, produces = MediaType.APPLICATION_JSON_VALUE)
@ -107,51 +98,4 @@ public interface DossierTemplateResource {
@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);
@Operation(summary = "Get the component mapping summaries of a DossierTemplate.", description = "None")
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_MAPPINGS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Component mapping views returned successfully."), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
ComponentMappingSummaries getComponentMappingSummaries(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);
@Operation(summary = "Upload a new component mapping to a DossierTemplate.", description = "None")
@PostMapping(value = PATH
+ DOSSIER_TEMPLATE_ID_PATH_VARIABLE
+ COMPONENT_MAPPINGS_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Component mapping uploaded successfully."), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified mapping is not found.")})
ComponentMappingSummary uploadMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
@Parameter(name = MAPPING_NAME_PARAM, description = "String of what the mapping should be accessible under. If left empty, the name of the file without the ending will be used as name.") @RequestParam(value = MAPPING_NAME_PARAM, required = false, defaultValue = "") String name,
@Parameter(name = ENCODING_PARAM, description = "The encoding of the file. Default is UTF-8.") @RequestParam(value = ENCODING_PARAM, required = false, defaultValue = "UTF-8") String encoding,
@Parameter(name = DELIMITER_PARAM, description = "The delimiter used in the file. Default is ','") @RequestParam(value = DELIMITER_PARAM, required = false, defaultValue = ",") char delimiter);
@Operation(summary = "Upload a new component mapping to a DossierTemplate.", description = "None")
@PutMapping(value = PATH
+ DOSSIER_TEMPLATE_ID_PATH_VARIABLE
+ COMPONENT_MAPPINGS_PATH
+ COMPONENT_MAPPING_ID_PATH_VARIABLE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Component mapping updated successfully."), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified mapping is not found.")})
ComponentMappingSummary updateMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
@PathVariable(COMPONENT_MAPPING_ID_PARAM) String componentMappingId,
@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
@Parameter(name = ENCODING_PARAM, description = "The encoding of the file. Default is utf8.") @RequestParam(value = ENCODING_PARAM, required = false, defaultValue = "UTF-8") String encoding,
@Parameter(name = DELIMITER_PARAM, description = "The delimiter used in the file. Default is ','") @RequestParam(value = DELIMITER_PARAM, required = false, defaultValue = ",") char delimiter);
@ResponseBody
@ResponseStatus(value = HttpStatus.OK)
@Operation(summary = "Returns file containing the specified mapping as a file.")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The DossierTemplate is not found.")})
@GetMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_MAPPINGS_PATH + COMPONENT_MAPPING_ID_PATH_VARIABLE, produces = MediaType.MULTIPART_FORM_DATA_VALUE)
ResponseEntity<?> downloadMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @PathVariable(COMPONENT_MAPPING_ID_PARAM) String componentMappingId);
@ResponseBody
@ResponseStatus(value = HttpStatus.OK)
@Operation(summary = "Deletes a specified mapping.")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "The DossierTemplate or the specified mapping is not found.")})
@DeleteMapping(value = PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + COMPONENT_MAPPINGS_PATH + COMPONENT_MAPPING_ID_PATH_VARIABLE, produces = MediaType.MULTIPART_FORM_DATA_VALUE)
ResponseEntity<?> deleteMapping(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId, @PathVariable(COMPONENT_MAPPING_ID_PARAM) String componentMappingId);
}

View File

@ -290,179 +290,6 @@ paths:
$ref: '#/components/schemas/FileAttributeDefinitionList'
description: |
Successfully returned the file attribute definitions for the specified dossier template.
/api/dossier-templates/{dossierTemplateId}/component-mappings:
get:
operationId: listAllMappings
tags:
- 1. Dossier Templates
summary: Returns a list of all existing component mappings in a dossier template
description: |
Retrieves a collection of component mapping views associated with a specific dossier template. Each component mapping view includes details such as name, number of lines, delimiter, encoding and other relevant metadata. This endpoint is useful for clients needing to understand what mappings are available under a particular dossier template.
parameters:
- $ref: '#/components/parameters/dossierTemplateId'
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/ComponentMappingSummaries'
description: |
Successfully returned the component mapping summaries for the specified dossier template.
"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: uploadMapping
summary: Upload a new component mapping to a DossierTemplate.
description: |
Utilize this endpoint to upload a new component mapping to a designated DossierTemplate.
The file is expected to be a comma separated file, whose first row are the labels for the columns of the file.
Further, it is expected that the data is rectangular, this means each row has the same size.
The rows in the file will be sorted the values in each column, starting with the left most and moving right recursively.
This enables much faster lookups down the line.
This means, it is highly beneficial to structure the csv such that the keys to query for appear in the first rows and the results to map in the last.
tags:
- 1. Dossier Templates
requestBody:
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/UploadRequest'
parameters:
- $ref: '#/components/parameters/dossierTemplateId'
- $ref: '#/components/parameters/mappingName'
- $ref: '#/components/parameters/encoding'
- $ref: '#/components/parameters/delimiter'
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/ComponentMappingSummary'
description: |
Component mapping uploaded successfully and returned the component mapping summary.
"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'
/api/dossier-templates/{dossierTemplateId}/component-mappings/{comonentMappingId}:
get:
operationId: downloadMappingFile
tags:
- 1. Dossier Templates
summary: Download a specific component mapping file of a specific dossier template.
description: |
Utilize this endpoint to download a specific component mapping file of a designated dossier template.
The file is named the same and encoded the same as when it was uploaded, but it's sorting might have changed to provide faster lookups.
A component mapping file may be used in the component rules to relate components to existing master data.
parameters:
- $ref: '#/components/parameters/dossierTemplateId'
- $ref: '#/components/parameters/componentMappingId'
responses:
"200":
headers:
Content-Disposition:
schema:
type: string
example: attachment; filename*=utf-8''mapping.csv
content:
text/plain; charset=utf-8:
schema:
type: string
description: |
Successfully downloaded the requested component mapping.
"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'
put:
operationId: updateMapping
summary: Update an existing component mapping of a DossierTemplate.
description: Updates an existing component mapping,
tags:
- 1. Dossier Templates
requestBody:
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/UploadRequest'
parameters:
- $ref: '#/components/parameters/dossierTemplateId'
- $ref: '#/components/parameters/componentMappingId'
- $ref: '#/components/parameters/encoding'
- $ref: '#/components/parameters/delimiter'
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/ComponentMappingSummary'
description: |
Component mapping uploaded successfully and returned the component mapping summary.
"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'
delete:
operationId: deleteMappingFile
tags:
- 1. Dossier Templates
summary: Delete a specific component mapping file of a specific dossier template.
description: |
Utilize this endpoint to delete a specific component mapping file of a designated dossier template.
parameters:
- $ref: '#/components/parameters/dossierTemplateId'
- $ref: '#/components/parameters/componentMappingId'
responses:
"204":
description: |
Successfully deleted the requested component mapping.
"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'
/api/dossier-templates/{dossierTemplateId}/dossiers:
get:
operationId: getDossiers
@ -918,6 +745,179 @@ paths:
$ref: '#/components/responses/403'
"500":
$ref: '#/components/responses/500'
/api/dossier-templates/{dossierTemplateId}/component-mappings:
get:
operationId: listAllMappings
tags:
- 4. Components
summary: Returns a list of all existing component mappings in a dossier template
description: |
Retrieves a collection of component mapping views associated with a specific dossier template. Each component mapping view includes details such as name, number of lines, delimiter, encoding and other relevant metadata. This endpoint is useful for clients needing to understand what mappings are available under a particular dossier template.
parameters:
- $ref: '#/components/parameters/dossierTemplateId'
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/ComponentMappingSummary'
description: |
Successfully returned the component mapping summary for the specified dossier template.
"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: uploadMapping
summary: Upload a new component mapping to a DossierTemplate.
description: |
Utilize this endpoint to upload a new component mapping to a designated DossierTemplate.
The file is expected to be a comma separated file, whose first row are the labels for the columns of the file.
Further, it is expected that the data is rectangular, this means each row has the same size.
The rows in the file will be sorted the values in each column, starting with the left most and moving right recursively.
This enables much faster lookups down the line.
This means, it is highly beneficial to structure the CSV File such that the keys to query for appear in the first rows and the results to map in the last.
tags:
- 4. Components
requestBody:
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/UploadRequest'
parameters:
- $ref: '#/components/parameters/dossierTemplateId'
- $ref: '#/components/parameters/mappingName'
- $ref: '#/components/parameters/encoding'
- $ref: '#/components/parameters/delimiter'
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/ComponentMappingMetadata'
description: |
Component mapping uploaded successfully and returned the component mapping metadata.
"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'
/api/dossier-templates/{dossierTemplateId}/component-mappings/{comonentMappingId}:
get:
operationId: downloadMappingFile
tags:
- 4. Components
summary: Download a specific component mapping file of a specific dossier template.
description: |
Utilize this endpoint to download a specific component mapping file of a designated dossier template.
The file is named the same and encoded the same as when it was uploaded, but it's sorting might have changed to provide faster lookups.
A component mapping file may be used in the component rules to relate components to existing master data.
parameters:
- $ref: '#/components/parameters/dossierTemplateId'
- $ref: '#/components/parameters/componentMappingId'
responses:
"200":
headers:
Content-Disposition:
schema:
type: string
example: attachment; filename*=utf-8''mapping.csv
content:
text/plain; charset=utf-8:
schema:
type: string
description: |
Successfully downloaded the requested component mapping.
"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'
put:
operationId: updateMapping
summary: Update an existing component mapping of a DossierTemplate.
description: Updates an existing component mapping,
tags:
- 4. Components
requestBody:
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/UploadRequest'
parameters:
- $ref: '#/components/parameters/dossierTemplateId'
- $ref: '#/components/parameters/componentMappingId'
- $ref: '#/components/parameters/encoding'
- $ref: '#/components/parameters/delimiter'
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/ComponentMappingMetadata'
description: |
Component mapping uploaded successfully and returned the component mapping metadata.
"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'
delete:
operationId: deleteMappingFile
tags:
- 4. Components
summary: Delete a specific component mapping file of a specific dossier template.
description: |
Utilize this endpoint to delete a specific component mapping file of a designated dossier template.
parameters:
- $ref: '#/components/parameters/dossierTemplateId'
- $ref: '#/components/parameters/componentMappingId'
responses:
"204":
description: |
Successfully deleted the requested component mapping.
"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'
/api/license/active/usage:
post:
operationId: getReport
@ -2063,14 +2063,14 @@ components:
- 8130acf6-4910-4123-827c-caacd8111402
dossierStatusId: b8280985-f558-43c0-852a-a3fa86803548
ComponentMappingSummary:
ComponentMappingMetadata:
description: |
The `ComponentMappingSummary` object represents the metadata of a component mapping csv file. These csv files may be used in the component rules to relate components to an existing knowledge base.
The `ComponentMappingMetadata` object represents the metadata of a component mapping csv file. These CSV files may be used in the component rules to relate components to an existing knowledge base.
type: object
properties:
id:
description: |
A unique identifier for the component mapping summary. It's generated automatically. Use this to retrieve a specific component mapping file.
A unique identifier for the component mapping metadata. It's generated automatically. Use this to retrieve a specific component mapping file.
type: string
name:
description: |
@ -2122,13 +2122,13 @@ components:
numberOfLines: 100
encoding: UTF-8
delimiter: ','
ComponentMappingSummaries:
ComponentMappingSummary:
description: |
The `ComponentMappingSummaries` object represents a collection of ComponentMappingSummary.
The `ComponentMappingSummary` object represents a collection of ComponentMappingMetadata.
type: object
example:
dossierTemplateId: 1e07cde0-d36a-4ab7-b389-494ca694a0cb
componentMappingSummaries:
componentMappingMetadata:
- id: 24ff9c3c-4863-4aea-8eda-cab8838b9192
name: MasterDataMapping
fileName: master_data.csv
@ -2156,15 +2156,15 @@ components:
The identifier of the dossier template associated with the component mapping summaries.
type: string
format: uuid
componentMappingSummaries:
ComponentMappingMetadata:
description: |
A list of component mapping summaries associated with this dossier template.
A list of component mapping metadata associated with this dossier template.
type: array
items:
$ref: "#/components/schemas/ComponentMappingSummary"
$ref: "#/components/schemas/ComponentMappingMetadata"
required:
- dossierTemplateId
- componentMappingSummaries
- ComponentMappingSummary
DossierTemplate:
description: |
The `DossierTemplate` object represents the blueprint for creating and

View File

@ -3,11 +3,10 @@ package com.iqser.red.service.persistence.management.v1.processor.mapper;
import java.util.List;
import org.mapstruct.Mapper;
import org.mapstruct.MappingConstants;
import org.mapstruct.factory.Mappers;
import com.iqser.red.service.persistence.management.v1.processor.entity.ComponentMappingEntity;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetaData;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata;
@Mapper
public interface ComponentMappingEntityMapper {
@ -15,15 +14,15 @@ public interface ComponentMappingEntityMapper {
ComponentMappingEntityMapper INSTANCE = Mappers.getMapper(ComponentMappingEntityMapper.class);
ComponentMappingMetaData toComponentMappingMetaData(ComponentMappingEntity componentMappingMetaData);
ComponentMappingMetadata toComponentMappingMetaData(ComponentMappingEntity componentMappingMetaData);
List<ComponentMappingMetaData> toComponentMappingMetaDataList(List<ComponentMappingEntity> componentMappingMetaData);
List<ComponentMappingMetadata> toComponentMappingMetaDataList(List<ComponentMappingEntity> componentMappingMetaData);
ComponentMappingEntity toComponentMappingEntity(ComponentMappingMetaData componentMappingSummary);
ComponentMappingEntity toComponentMappingEntity(ComponentMappingMetadata componentMappingSummary);
List<ComponentMappingEntity> toComponentMappingEntityList(List<ComponentMappingMetaData> componentMappingSummary);
List<ComponentMappingEntity> toComponentMappingEntityList(List<ComponentMappingMetadata> componentMappingSummary);
}

View File

@ -2,8 +2,8 @@ package com.iqser.red.service.persistence.management.v1.processor.model;
import java.io.File;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetaData;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata;
public record ComponentMapping(ComponentMappingMetaData componentMappingMetaData, File mappingFile) {
public record ComponentMapping(ComponentMappingMetadata metaData, File file) {
}

View File

@ -6,6 +6,8 @@ import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
@ -16,19 +18,19 @@ import java.util.UUID;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.model.ComponentMappingDownloadModel;
import com.iqser.red.service.persistence.management.v1.processor.entity.ComponentMappingEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.mapper.ComponentMappingEntityMapper;
import com.iqser.red.service.persistence.management.v1.processor.model.ComponentMapping;
import com.iqser.red.service.persistence.management.v1.processor.model.ComponentMappingDownloadModel;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetaData;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata;
import com.opencsv.CSVParserBuilder;
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.CSVWriter;
import com.opencsv.exceptions.CsvException;
import io.undertow.util.BadRequestException;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
@ -46,21 +48,21 @@ public class ComponentMappingService {
static CSVSorter CSV_SORTER = new CSVSorter();
public List<ComponentMappingMetaData> getMetaDataByDossierTemplateId(String dossierTemplateId) {
public List<ComponentMappingMetadata> getMetaDataByDossierTemplateId(String dossierTemplateId) {
List<ComponentMappingEntity> entities = componentMappingPersistenceService.getByDossierTemplateId(dossierTemplateId);
return mappingEntityMapper.toComponentMappingMetaDataList(entities);
}
public ComponentMappingMetaData getMetaData(String mappingId) {
public ComponentMappingMetadata getMetaData(String mappingId) {
return mappingEntityMapper.toComponentMappingMetaData(componentMappingPersistenceService.getEntityById(mappingId));
}
@SneakyThrows
public ComponentMappingMetaData update(String mappingId, String encoding, char delimiter, File mappingFile) {
public ComponentMappingMetadata update(String mappingId, String encoding, char delimiter, File mappingFile) {
ComponentMappingEntity entity = componentMappingPersistenceService.getEntityById(mappingId);
@ -69,18 +71,18 @@ public class ComponentMappingService {
@SneakyThrows
public ComponentMappingMetaData create(String dossierTemplateId, String name, String fileName, char delimiter, String encoding, File mappingFile) {
public ComponentMappingMetadata create(String dossierTemplateId, String name, String fileName, char delimiter, String encoding, File mappingFile) {
if (componentMappingPersistenceService.existsByNameAndDossierTemplateId(name, dossierTemplateId)) {
throw new BadRequestException("A mapping with this name already exists in the dossier template!");
}
String id = UUID.randomUUID().toString();
String storageId = buildStorageId(dossierTemplateId, id, name, fileName);
ComponentMappingEntity entity = ComponentMappingEntity.builder()
.id(id)
.dossierTemplate(dossierTemplatePersistenceService.getDossierTemplate(dossierTemplateId))
.storageId(dossierTemplateId + "/" + id)
.storageId(storageId)
.name(name)
.fileName(fileName)
.build();
@ -90,9 +92,9 @@ public class ComponentMappingService {
@SneakyThrows
private ComponentMappingMetaData updateOrCreate(ComponentMappingEntity entity, String encoding, char delimiter, File mappingFile) {
private ComponentMappingMetadata updateOrCreate(ComponentMappingEntity entity, String encoding, char delimiter, File mappingFile) {
Charset charset = getCharset(entity);
Charset charset = resolveCharset(encoding);
CsvStats stats = sortCSVFile(delimiter, mappingFile, charset);
@ -108,14 +110,16 @@ public class ComponentMappingService {
}
@SneakyThrows
private static Charset getCharset(ComponentMappingEntity entity) {
private static Charset resolveCharset(String encoding) {
try {
return Charset.forName(entity.getEncoding());
} catch (Exception e) {
throw new BadRequestException(e);
return Charset.forName(encoding);
} catch (IllegalCharsetNameException e) {
throw new BadRequestException("Invalid character encoding: " + encoding);
} catch (UnsupportedCharsetException e) {
throw new BadRequestException("Unsupported character encoding: " + encoding);
} catch (IllegalArgumentException e) {
throw new BadRequestException("Encoding can't be null.");
}
}
@ -185,13 +189,19 @@ public class ComponentMappingService {
}
private ComponentMapping downloadFileAndCreateMapping(Path outputDir, ComponentMappingMetaData metaData) {
private ComponentMapping downloadFileAndCreateMapping(Path outputDir, ComponentMappingMetadata metaData) {
File mappingFile = componentMappingPersistenceService.downloadMappingFileToFolder(metaData.getStorageId(), metaData.getFileName(), outputDir);
return new ComponentMapping(metaData, mappingFile);
}
public static String buildStorageId(String dossierTemplateId, String id, String name, String fileName) {
return dossierTemplateId + "/" + id + "_" + name + "_" + fileName;
}
private static class CSVSorter implements Comparator<String[]> {
@Override

View File

@ -61,7 +61,7 @@ import com.iqser.red.service.persistence.management.v1.processor.settings.FileMa
import com.iqser.red.service.persistence.management.v1.processor.utils.FileUtils;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.WatermarkModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetaData;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierAttributeConfig;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplate;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplateStatus;
@ -148,7 +148,7 @@ public class DossierTemplateImportService {
Map<String, List<String>> typeEntriesMap = new HashMap<>();
Map<String, List<String>> typeFalsePositivesMap = new HashMap<>();
Map<String, List<String>> typeFalseRecommendationsMap = new HashMap<>();
List<ComponentMappingMetaData> componentMappingMetaData = new LinkedList<>();
List<ComponentMappingMetadata> componentMappingMetaData = new LinkedList<>();
while ((ze = zis.getNextZipEntry()) != null) {
log.debug("---> " + ze.getName() + " ---- " + ze.isDirectory());

View File

@ -90,6 +90,8 @@ public class FileStatusService {
ViewedPagesPersistenceService viewedPagesPersistenceService;
FileManagementServiceSettings fileManagementServiceSettings;
LayoutParsingRequestFactory layoutParsingRequestFactory;
ComponentMappingService componentMappingService;
WebsocketService websocketService;
@Transactional
@ -252,6 +254,7 @@ public class FileStatusService {
.sectionsToReanalyse(sectionsToReanalyse)
.fileId(fileId)
.manualRedactions(manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.allWithoutDeleted()))
.componentMappings(componentMappingService.getMetaDataByDossierTemplateId(dossierTemplate.getId()))
.dossierTemplateId(dossier.getDossierTemplateId())
.lastProcessed(fileModel.getLastProcessed())
.fileAttributes(convertAttributes(fileEntity.getFileAttributes(), dossier.getDossierTemplateId()))

View File

@ -30,7 +30,6 @@ import com.iqser.red.service.persistence.management.v1.processor.exception.NotFo
import com.iqser.red.service.persistence.management.v1.processor.model.ComponentMapping;
import com.iqser.red.service.persistence.management.v1.processor.model.DownloadJob;
import com.iqser.red.service.persistence.management.v1.processor.service.ColorsService;
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentMappingPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentMappingService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
import com.iqser.red.service.persistence.management.v1.processor.service.WatermarkService;
@ -247,14 +246,15 @@ public class DossierTemplateExportService {
for (ComponentMapping componentMapping : componentMappings) {
Path mappingFilePath = mappingDir.resolve(componentMapping.componentMappingMetaData().getFileName());
Path mappingFilePath = mappingDir.resolve(componentMapping.metaData().getFileName());
fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(ExportFilename.COMPONENT_MAPPINGS.getFilename(),
componentMapping.componentMappingMetaData().getName() + JSON_EXT,
componentMapping.metaData().getName() + JSON_EXT,
objectMapper.writeValueAsBytes(componentMapping)));
fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(ExportFilename.COMPONENT_MAPPINGS.getFilename(),
componentMapping.componentMappingMetaData().getFileName(),
componentMapping.metaData().getName() + "-" + componentMapping.metaData()
.getFileName(),
Files.readAllBytes(mappingFilePath)));
}

View File

@ -7,6 +7,7 @@ import java.util.List;
import java.util.Set;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
import com.iqser.red.service.persistence.service.v1.api.shared.model.component.ComponentMappingMetadata;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -34,5 +35,8 @@ public class AnalyzeRequest {
@Builder.Default
private List<FileAttribute> fileAttributes = new ArrayList<>();
@Builder.Default
private List<ComponentMappingMetadata> componentMappings = new ArrayList<>();
}