Merge branch 'RED-9375' into 'master'
RED-9375: fix component mapping endpoint validation Closes RED-9375 See merge request redactmanager/persistence-service!561
This commit is contained in:
commit
c34af58aa0
@ -6,6 +6,7 @@ import static com.iqser.red.service.persistence.management.v1.processor.roles.Ac
|
||||
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;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@ -208,20 +209,28 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
String nameToUse = Strings.isNullOrEmpty(name) ? file.getOriginalFilename() : name;
|
||||
|
||||
if (Strings.isNullOrEmpty(nameToUse)) {
|
||||
throw new BadRequestException("The provided file name is not valid!");
|
||||
if (Strings.isNullOrEmpty(file.getOriginalFilename()) || !file.getOriginalFilename().endsWith(".csv")) {
|
||||
throw new BadRequestException(format("File name \"%s\" does not end with .csv", file.getOriginalFilename()));
|
||||
}
|
||||
|
||||
if (Strings.isNullOrEmpty(delimiter) || delimiter.length() != 1) {
|
||||
throw new BadRequestException("The provided delimiter is not valid! Only a single character is allowed.");
|
||||
String fileName = file.getOriginalFilename();
|
||||
|
||||
String nameToUse = Strings.isNullOrEmpty(name) ? fileName.replaceAll(".csv$", "") : name;
|
||||
|
||||
if (Strings.isNullOrEmpty(nameToUse)) {
|
||||
throw new BadRequestException(format("The provided file name \"%s\" is not valid!", nameToUse));
|
||||
}
|
||||
|
||||
if (Strings.isNullOrEmpty(delimiter)) {
|
||||
throw new BadRequestException("The provided delimiter is not valid! Can't be null or empty.");
|
||||
} else if (delimiter.length() != 1) {
|
||||
throw new BadRequestException(format("The provided delimiter %s is not valid! Only a single character is allowed.", delimiter));
|
||||
}
|
||||
char cleanDelimiter = delimiter.charAt(0);
|
||||
|
||||
Path mappingFile = saveToFile(file);
|
||||
|
||||
try {
|
||||
String fileName = file.getOriginalFilename() == null ? nameToUse + ".csv" : file.getOriginalFilename();
|
||||
|
||||
ComponentMappingMetadata metaData = componentMappingService.create(dossierTemplateId, nameToUse, fileName, cleanDelimiter, encoding, mappingFile.toFile());
|
||||
|
||||
@ -236,14 +245,42 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
|
||||
public ComponentMappingMetadataModel updateMapping(String dossierTemplateId, String componentMappingId, MultipartFile file, String encoding, char delimiter) {
|
||||
public ComponentMappingMetadataModel updateMapping(String dossierTemplateId, String componentMappingId, MultipartFile file, String name, String encoding, String delimiter) {
|
||||
|
||||
dossierTemplatePersistenceService.checkDossierTemplateExistsOrElseThrow404(dossierTemplateId);
|
||||
|
||||
if (Strings.isNullOrEmpty(file.getOriginalFilename()) || !file.getOriginalFilename().endsWith(".csv")) {
|
||||
throw new BadRequestException(format("File name \"%s\" does not end with .csv", file.getOriginalFilename()));
|
||||
}
|
||||
|
||||
String fileName = file.getOriginalFilename();
|
||||
|
||||
String nameToUse = Strings.isNullOrEmpty(name) ? fileName.replaceAll(".csv$", "") : name;
|
||||
|
||||
if (Strings.isNullOrEmpty(nameToUse)) {
|
||||
throw new BadRequestException(format("The provided file name \"%s\" is not valid!", nameToUse));
|
||||
}
|
||||
|
||||
if (Strings.isNullOrEmpty(delimiter)) {
|
||||
throw new BadRequestException("The provided delimiter is not valid! Can't be null or empty.");
|
||||
} else if (delimiter.length() != 1) {
|
||||
throw new BadRequestException(format("The provided delimiter %s is not valid! Only a single character is allowed.", delimiter));
|
||||
}
|
||||
char cleanDelimiter = delimiter.charAt(0);
|
||||
|
||||
if (Strings.isNullOrEmpty(delimiter) || delimiter.length() != 1) {
|
||||
throw new BadRequestException("The provided delimiter is not valid! Only a single character is allowed.");
|
||||
}
|
||||
|
||||
Path mappingFile = saveToFile(file);
|
||||
|
||||
try {
|
||||
ComponentMappingMetadata resultMetaData = componentMappingService.update(dossierTemplateId, componentMappingId, encoding, delimiter, mappingFile.toFile());
|
||||
ComponentMappingMetadata resultMetaData = componentMappingService.update(dossierTemplateId,
|
||||
componentMappingId,
|
||||
nameToUse,
|
||||
encoding,
|
||||
cleanDelimiter,
|
||||
mappingFile.toFile());
|
||||
|
||||
return componentMappingMapper.toModel(resultMetaData);
|
||||
} finally {
|
||||
@ -508,7 +545,7 @@ public class DossierTemplateControllerV2 implements DossierTemplateResource {
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(rulesUploadRequest.getDossierTemplateId())
|
||||
.category(AuditCategory.DOSSIER_TEMPLATE.name())
|
||||
.message(String.format("%s rules have been %s", rulesUploadRequest.getRuleFileType(), dryRun ? "validated" : "updated"))
|
||||
.message(format("%s rules have been %s", rulesUploadRequest.getRuleFileType(), dryRun ? "validated" : "updated"))
|
||||
.build());
|
||||
|
||||
return new ResponseEntity<>(rulesValidationResponse, HttpStatus.OK);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.iqser.red.service.persistence.service.v2.api.external.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierAttributeDefinitionList;
|
||||
import com.iqser.red.service.persistence.service.v2.api.external.model.DossierStatusDefinitionList;
|
||||
@ -152,8 +153,9 @@ public interface DossierTemplateResource {
|
||||
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 = 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);
|
||||
@Parameter(name = DELIMITER_PARAM, description = "The delimiter used in the file. Default is ','") @RequestParam(value = DELIMITER_PARAM, required = false, defaultValue = ",") String delimiter);
|
||||
|
||||
|
||||
@ResponseBody
|
||||
|
||||
@ -539,6 +539,7 @@ paths:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/dossierTemplateId'
|
||||
- $ref: '#/components/parameters/componentMappingId'
|
||||
- $ref: '#/components/parameters/mappingName'
|
||||
- $ref: '#/components/parameters/encoding'
|
||||
- $ref: '#/components/parameters/delimiter'
|
||||
responses:
|
||||
|
||||
@ -6,9 +6,12 @@ import java.nio.file.Path;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
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.entity.ComponentMappingEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
@ -16,6 +19,7 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist
|
||||
import com.iqser.red.storage.commons.service.StorageService;
|
||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
@ -70,7 +74,11 @@ public class ComponentMappingPersistenceService {
|
||||
public void updateOrCreate(String storageId, File mappingFile, ComponentMappingEntity entity) {
|
||||
|
||||
entity.setChangedDate(OffsetDateTime.now());
|
||||
repository.saveAndFlush(entity);
|
||||
try {
|
||||
repository.saveAndFlush(entity);
|
||||
} catch (DataAccessException ex) {
|
||||
throw new BadRequestException("Failed to save component mapping metadata due to invalid data.", ex);
|
||||
}
|
||||
try (var in = new FileInputStream(mappingFile)) {
|
||||
storageService.storeObject(TenantContext.getTenantId(), storageId, in);
|
||||
}
|
||||
@ -101,6 +109,7 @@ public class ComponentMappingPersistenceService {
|
||||
return outputFile;
|
||||
}
|
||||
|
||||
|
||||
public void setVersion(String componentMappingId, Integer version) {
|
||||
|
||||
repository.updateVersion(componentMappingId, version);
|
||||
|
||||
@ -62,11 +62,11 @@ public class ComponentMappingService {
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public ComponentMappingMetadata update(String dossierTemplateId, String mappingId, String encoding, char delimiter, File mappingFile) {
|
||||
public ComponentMappingMetadata update(String dossierTemplateId, String mappingId, String name, String encoding, char delimiter, File mappingFile) {
|
||||
|
||||
ComponentMappingEntity entity = componentMappingPersistenceService.getEntityById(dossierTemplateId, mappingId);
|
||||
|
||||
return updateOrCreate(entity, encoding, delimiter, mappingFile);
|
||||
return updateOrCreate(entity, name, encoding, delimiter, mappingFile);
|
||||
}
|
||||
|
||||
|
||||
@ -83,21 +83,22 @@ public class ComponentMappingService {
|
||||
.id(id)
|
||||
.dossierTemplate(dossierTemplatePersistenceService.getDossierTemplate(dossierTemplateId))
|
||||
.storageId(storageId)
|
||||
.name(name)
|
||||
.fileName(fileName)
|
||||
.build();
|
||||
|
||||
return updateOrCreate(entity, encoding, delimiter, mappingFile);
|
||||
return updateOrCreate(entity, name, encoding, delimiter, mappingFile);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
private ComponentMappingMetadata updateOrCreate(ComponentMappingEntity entity, String encoding, char delimiter, File mappingFile) {
|
||||
private ComponentMappingMetadata updateOrCreate(ComponentMappingEntity entity, String name, String encoding, char delimiter, File mappingFile) {
|
||||
|
||||
Charset charset = resolveCharset(encoding);
|
||||
|
||||
CsvStats stats = sortCSVFile(delimiter, mappingFile, charset);
|
||||
|
||||
entity.setName(name);
|
||||
entity.setDelimiter(delimiter);
|
||||
entity.setEncoding(encoding);
|
||||
entity.setNumberOfLines(stats.numberOfLines());
|
||||
@ -140,10 +141,17 @@ public class ComponentMappingService {
|
||||
|
||||
columnLabels = rows.remove(0); // remove header row
|
||||
|
||||
if (Arrays.stream(columnLabels).distinct().count() < columnLabels.length) {
|
||||
if (Arrays.stream(columnLabels)
|
||||
.distinct()
|
||||
.count() < columnLabels.length) {
|
||||
throw new BadRequestException("Column labels may not contain duplicates!");
|
||||
}
|
||||
|
||||
if (rows.stream()
|
||||
.anyMatch(row -> row.length != columnLabels.length)) {
|
||||
throw new BadRequestException("Data in csv must be rectangular!");
|
||||
}
|
||||
|
||||
numberOfLines = (int) reader.getLinesRead() - 1; // subtract header row
|
||||
|
||||
rows.sort(CSV_SORTER);
|
||||
|
||||
@ -86,7 +86,7 @@ public interface DossierRepository extends JpaRepository<DossierEntity, String>
|
||||
|
||||
|
||||
@Query("select d.id from DossierEntity d where d.dossierTemplateId = :dossierTemplateId")
|
||||
Set<String> findIdsByDossierTemplateId(String dossierTemplateId);
|
||||
Set<String> findIdsByDossierTemplateId(@Param("dossierTemplateId") String dossierTemplateId);
|
||||
|
||||
|
||||
@Modifying
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user