RED-9868 - Import older template zip with incompatible component rules breaks the stack #702

Merged
corina.olariu.ext1 merged 1 commits from RED-9868-update into master 2024-08-29 10:40:36 +02:00
3 changed files with 280 additions and 203 deletions

View File

@ -96,7 +96,34 @@ public interface DossierTemplateResource {
@ResponseStatus(value = HttpStatus.NO_CONTENT)
@PostMapping(value = DOSSIER_TEMPLATE_PATH + IMPORT_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Receives an archive to import", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Archive have successfully imported"), @ApiResponse(responseCode = "400", description = "Validation failed during import"), @ApiResponse(responseCode = "404", description = "The dossier template to update does not exist")})
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Archive have successfully imported"), @ApiResponse(responseCode = "400", description = "Import process stuck in one of the steps:"
+ "0 - Reading the archive content\n"
+ "\n"
+ "1 - store information about the dossier template\n"
+ "\n"
+ "2 - store the colors\n"
+ "\n"
+ "3 - store the watermarks\n"
+ "\n"
+ "4 - store the dossier status\n"
+ "\n"
+ "5 - store the dossier attributes\n"
+ "\n"
+ "6 - store the file attributes\n"
+ "\n"
+ "7 - store the report templates\n"
+ "\n"
+ "8 - store the legal basis\n"
+ "\n"
+ "9 - store the file attribute configuration\n"
+ "\n"
+ "10 - store the component definitions\n"
+ "\n"
+ "11 - store the component mappings\n"
+ "\n"
+ "12 - store the types and entities\n"
+ "\n"
+ "13 - store the rules and component rules"), @ApiResponse(responseCode = "404", description = "The dossier template to update does not exist")})
DossierTemplateModel importDossierTemplate(@Schema(type = "string", format = "binary", name = "file") @RequestPart(name = "file") MultipartFile file,
@RequestParam(value = DOSSIER_TEMPLATE_ID, required = false) String dossierTemplateId,
@RequestParam(value = "updateExistingDossierTemplate", required = false, defaultValue = "false") boolean updateExistingDossierTemplate);

View File

@ -101,7 +101,12 @@ public class DossierTemplateImportService {
public String importDossierTemplate(ImportDossierTemplateRequest request) {
ImportTemplateResult archiveResult = readDossierTemplateImportArchive(request);
ImportTemplateResult archiveResult;
try {
archiveResult = readDossierTemplateImportArchive(request);
} catch (Exception e) {
throw new BadRequestException("The import process failed in step: 0 - while reading the archive content with error: " + e.getMessage());
}
return importDossierTemplate(archiveResult).getDossierTemplateId();
}
@ -121,11 +126,13 @@ public class DossierTemplateImportService {
return dossierTemplateArchiveReader.buildResult();
}
@Observed(name = "DossierTemplateImportService", contextualName = "import-template")
public TemplateImportInfo importDossierTemplate(ImportTemplateResult request) {
long start = System.currentTimeMillis();
String dossierTemplateId;
int importStep = 1;
var dossierTemplateMeta = request.getDossierTemplate();
TemplateImportInfo templateImportInfo = TemplateImportInfo.builder().build();
@ -136,217 +143,261 @@ public class DossierTemplateImportService {
existingDossierTemplate = dossierTemplateOptional.orElse(null);
}
if (existingDossierTemplate != null) {
dossierTemplateId = existingDossierTemplate.getId();
try {
// override the existing dossier template
updateDossierTemplateMeta(existingDossierTemplate, dossierTemplateMeta, request.getUserId());
dossierTemplateRepository.save(existingDossierTemplate);
if (existingDossierTemplate != null) {
dossierTemplateId = existingDossierTemplate.getId();
existingDossierTemplate.setDossierTemplateStatus(DossierTemplateStatus.valueOf(dossierTemplatePersistenceService.computeDossierTemplateStatus(existingDossierTemplate)
.name()));
// override the existing dossier template
updateDossierTemplateMeta(existingDossierTemplate, dossierTemplateMeta, request.getUserId());
dossierTemplateRepository.save(existingDossierTemplate);
// set colors
this.setColors(dossierTemplateId, request.getColors());
existingDossierTemplate.setDossierTemplateStatus(DossierTemplateStatus.valueOf(dossierTemplatePersistenceService.computeDossierTemplateStatus(
existingDossierTemplate).name()));
// set watermarks
if (CollectionUtils.isNotEmpty(request.getWatermarks())) {
Set<String> toSetWatermarks = request.getWatermarks()
.stream()
.map(WatermarkModel::getName)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
var currentWatermarkConfigs = watermarkService.getWatermarksForDossierTemplateId(dossierTemplateId);
Set<WatermarkEntity> configsToRemove = currentWatermarkConfigs.stream()
.filter(c -> !toSetWatermarks.contains(c.getName()))
.collect(Collectors.toSet());
var watermarkNameToEntity = currentWatermarkConfigs.stream()
.collect(Collectors.toMap(WatermarkEntity::getName, Function.identity()));
// set colors
importStep = 2;
this.setColors(dossierTemplateId, request.getColors());
request.getWatermarks()
.forEach(watermark -> {
log.info("watermark to add: " + watermark.getName());
Long initialId = watermark.getId();
if (!watermarkNameToEntity.isEmpty() && watermarkNameToEntity.get(watermark.getName()) != null) {
// set watermarks
if (CollectionUtils.isNotEmpty(request.getWatermarks())) {
importStep = 3;
Set<String> toSetWatermarks = request.getWatermarks()
.stream()
.map(WatermarkModel::getName)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
var currentWatermarkConfigs = watermarkService.getWatermarksForDossierTemplateId(dossierTemplateId);
Set<WatermarkEntity> configsToRemove = currentWatermarkConfigs.stream()
.filter(c -> !toSetWatermarks.contains(c.getName()))
.collect(Collectors.toSet());
var watermarkNameToEntity = currentWatermarkConfigs.stream()
.collect(Collectors.toMap(WatermarkEntity::getName, Function.identity()));
watermark.setId(watermarkNameToEntity.get(watermark.getName()).getId());
} else {
request.getWatermarks()
.forEach(watermark -> {
log.info("watermark to add: " + watermark.getName());
Long initialId = watermark.getId();
if (!watermarkNameToEntity.isEmpty() && watermarkNameToEntity.get(watermark.getName()) != null) {
watermark.setId(watermarkNameToEntity.get(watermark.getName()).getId());
} else {
watermark.setId(null);
}
watermark.setDossierTemplateId(dossierTemplateId);
var entity = watermarkService.createOrUpdateWatermark(watermark);
templateImportInfo.getLongMapping().put(initialId, entity.getId());
});
configsToRemove.forEach(watermark -> watermarkService.deleteWatermark(watermark.getId()));
}
// dossier status
importStep = 4;
if (CollectionUtils.isNotEmpty(request.getDossierStatusInfos())) {
this.updateDossierStates(request, dossierTemplateId);
} else { // no states to add, delete current states
List<DossierStatusInfo> currentStates = dossierStatusPersistenceService.getAllDossierStatusForTemplate(dossierTemplateId);
currentStates.forEach(state -> dossierStatusPersistenceService.deleteDossierStatus(state.getId(), null));
}
// update dossier attributes
importStep = 5;
if (CollectionUtils.isNotEmpty(request.getDossierAttributesConfigs())) {
this.updateDossierAttributes(request, dossierTemplateId, templateImportInfo);
} else { // no dossier attributes to add, but delete existing ones
var currentConfigs = dossierAttributeConfigPersistenceService.getDossierAttributes(dossierTemplateId);
currentConfigs.forEach(da -> dossierAttributeConfigPersistenceService.deleteDossierAttribute(da.getId()));
}
//update file attributes
importStep = 6;
if (CollectionUtils.isNotEmpty(request.getFileAttributesConfigs())) {
this.updateFileAttributes(request, dossierTemplateId, templateImportInfo);
} else { // no file attributes to add, but delete existing
var currentConfigs = fileAttributeConfigPersistenceService.getFileAttributes(dossierTemplateId);
currentConfigs.forEach(fa -> fileAttributeConfigPersistenceService.deleteFileAttribute(fa.getId()));
}
//set report templates
importStep = 7;
var existingReports = reportTemplatePersistenceService.findByDossierTemplateId(dossierTemplateId);
List<String> reportsUpdated = new ArrayList<>();
if (CollectionUtils.isNotEmpty(request.getReportTemplateUploadRequests())) {
request.getReportTemplateUploadRequests()
.forEach(reportRequest -> {
reportRequest.setDossierTemplateId(dossierTemplateId);
var report = reportTemplateService.uploadTemplate(reportRequest);
reportsUpdated.add(report.getTemplateId());
});
}
// delete the reports that were not in the import
existingReports.forEach(r -> {
String storageId = r.getStorageId();
if (!reportsUpdated.contains(r.getTemplateId())) {
storageService.deleteObject(TenantContext.getTenantId(), storageId);
reportTemplatePersistenceService.delete(r.getTemplateId());
}
});
// set legal basis
importStep = 8;
if (CollectionUtils.isNotEmpty(request.getLegalBases())) {
legalBasisMappingPersistenceService.setLegalBasisMapping(dossierTemplateId, request.getLegalBases());
} else { // delete existing
legalBasisMappingPersistenceService.deleteLegalBasis(dossierTemplateId);
}
// file attribute general configuration
if (request.getFileAttributesGeneralConfiguration() != null) {
importStep = 9;
fileAttributeConfigPersistenceService.setFileAttributesGeneralConfig(dossierTemplateId,
convert(request.getFileAttributesGeneralConfiguration(),
FileAttributesGeneralConfigurationEntity.class));
}
// component definitions
importStep = 10;
if (CollectionUtils.isNotEmpty(request.getComponentDefinitions())) {
this.updateComponents(request, dossierTemplateId);
} else { // no components to add, but remove existing ones
List<ComponentDefinitionEntity> currentComponents = componentDefinitionPersistenceService.findComponentsByDossierTemplateId(dossierTemplateId);
this.deleteComponents(currentComponents);
}
//set component mappings
importStep = 11;
setComponentMappings(dossierTemplateId, request.getComponentMappings());
importStep = 12;
entityTypeImportService.updateTypes(dossierTemplateId, null, request.getEntityTypeImportModel());
} else {
// creates new dossier template
if (StringUtils.isEmpty(dossierTemplateMeta.getName())) {
throw new ConflictException("DossierTemplate name must be set");
}
dossierTemplateMeta.setId("");
this.validateDossierTemplateName(dossierTemplateMeta);
DossierTemplateEntity dossierTemplateEntity = new DossierTemplateEntity();
// order is important
BeanUtils.copyProperties(dossierTemplateMeta, dossierTemplateEntity);
dossierTemplateEntity.setId(UUID.randomUUID().toString());
dossierTemplateEntity.setDateAdded(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
dossierTemplateEntity.setCreatedBy(request.getUserId());
var loadedDossierTemplate = dossierTemplateRepository.save(dossierTemplateEntity);
loadedDossierTemplate.setDossierTemplateStatus(dossierTemplatePersistenceService.computeDossierTemplateStatus(loadedDossierTemplate));
dossierTemplateId = loadedDossierTemplate.getId();
// set colors
importStep = 2;
this.setColors(dossierTemplateId, request.getColors());
// set watermarks
if (CollectionUtils.isNotEmpty(request.getWatermarks())) {
importStep = 3;
request.getWatermarks()
.forEach(watermark -> {
Long initialId = watermark.getId();
watermark.setDossierTemplateId(dossierTemplateId);
watermark.setId(null);
}
watermark.setDossierTemplateId(dossierTemplateId);
var entity = watermarkService.createOrUpdateWatermark(watermark);
templateImportInfo.getLongMapping().put(initialId, entity.getId());
});
configsToRemove.forEach(watermark -> watermarkService.deleteWatermark(watermark.getId()));
}
// dossier status
if (CollectionUtils.isNotEmpty(request.getDossierStatusInfos())) {
this.updateDossierStates(request, dossierTemplateId);
} else { // no states to add, delete current states
List<DossierStatusInfo> currentStates = dossierStatusPersistenceService.getAllDossierStatusForTemplate(dossierTemplateId);
currentStates.forEach(state -> dossierStatusPersistenceService.deleteDossierStatus(state.getId(), null));
}
// update dossier attributes
if (CollectionUtils.isNotEmpty(request.getDossierAttributesConfigs())) {
this.updateDossierAttributes(request, dossierTemplateId, templateImportInfo);
} else { // no dossier attributes to add, but delete existing ones
var currentConfigs = dossierAttributeConfigPersistenceService.getDossierAttributes(dossierTemplateId);
currentConfigs.forEach(da -> dossierAttributeConfigPersistenceService.deleteDossierAttribute(da.getId()));
}
//update file attributes
if (CollectionUtils.isNotEmpty(request.getFileAttributesConfigs())) {
this.updateFileAttributes(request, dossierTemplateId, templateImportInfo);
} else { // no file attributes to add, but delete existing
var currentConfigs = fileAttributeConfigPersistenceService.getFileAttributes(dossierTemplateId);
currentConfigs.forEach(fa -> fileAttributeConfigPersistenceService.deleteFileAttribute(fa.getId()));
}
entityTypeImportService.updateTypes(dossierTemplateId, null, request.getEntityTypeImportModel());
if (CollectionUtils.isNotEmpty(request.getComponentDefinitions())) {
this.updateComponents(request, dossierTemplateId);
} else { // no components to add, but remove existing ones
List<ComponentDefinitionEntity> currentComponents = componentDefinitionPersistenceService.findComponentsByDossierTemplateId(dossierTemplateId);
this.deleteComponents(currentComponents);
}
//set report templates
var existingReports = reportTemplatePersistenceService.findByDossierTemplateId(dossierTemplateId);
List<String> reportsUpdated = new ArrayList<>();
if (CollectionUtils.isNotEmpty(request.getReportTemplateUploadRequests())) {
request.getReportTemplateUploadRequests()
.forEach(reportRequest -> {
reportRequest.setDossierTemplateId(dossierTemplateId);
var report = reportTemplateService.uploadTemplate(reportRequest);
reportsUpdated.add(report.getTemplateId());
});
}
// delete the reports that were not in the import
existingReports.forEach(r -> {
String storageId = r.getStorageId();
if (!reportsUpdated.contains(r.getTemplateId())) {
storageService.deleteObject(TenantContext.getTenantId(), storageId);
reportTemplatePersistenceService.delete(r.getTemplateId());
var en = watermarkService.createOrUpdateWatermark(watermark);
templateImportInfo.getLongMapping().put(initialId, en.getId());
});
}
});
// set legal basis
if (CollectionUtils.isNotEmpty(request.getLegalBases())) {
legalBasisMappingPersistenceService.setLegalBasisMapping(dossierTemplateId, request.getLegalBases());
} else { // delete existing
legalBasisMappingPersistenceService.deleteLegalBasis(dossierTemplateId);
}
} else {
// creates new dossier template
if (StringUtils.isEmpty(dossierTemplateMeta.getName())) {
throw new ConflictException("DossierTemplate name must be set");
}
dossierTemplateMeta.setId("");
this.validateDossierTemplateName(dossierTemplateMeta);
DossierTemplateEntity dossierTemplateEntity = new DossierTemplateEntity();
// order is important
BeanUtils.copyProperties(dossierTemplateMeta, dossierTemplateEntity);
dossierTemplateEntity.setId(UUID.randomUUID().toString());
dossierTemplateEntity.setDateAdded(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
dossierTemplateEntity.setCreatedBy(request.getUserId());
//set rules
var loadedDossierTemplate = dossierTemplateRepository.save(dossierTemplateEntity);
loadedDossierTemplate.setDossierTemplateStatus(dossierTemplatePersistenceService.computeDossierTemplateStatus(loadedDossierTemplate));
dossierTemplateId = loadedDossierTemplate.getId();
// set colors
this.setColors(dossierTemplateId, request.getColors());
// set watermarks
if (CollectionUtils.isNotEmpty(request.getWatermarks())) {
request.getWatermarks()
.forEach(watermark -> {
Long initialId = watermark.getId();
watermark.setDossierTemplateId(dossierTemplateId);
watermark.setId(null);
var en = watermarkService.createOrUpdateWatermark(watermark);
templateImportInfo.getLongMapping().put(initialId, en.getId());
});
}
// dossier status
if (CollectionUtils.isNotEmpty(request.getDossierStatusInfos())) {
request.getDossierStatusInfos()
.forEach(state -> {
state.setId(null);
this.updateDossierStatus(dossierTemplateId, state);
});
}
//set dossier attributes
if (CollectionUtils.isNotEmpty(request.getDossierAttributesConfigs())) {
request.getDossierAttributesConfigs()
.forEach(da -> {
String initialId = da.getId();
da.setId(null); // in order to create a new dossier attribute
var e = dossierAttributeConfigPersistenceService.addOrUpdateDossierAttribute(dossierTemplateId, convert(da, DossierAttributeConfigEntity.class));
templateImportInfo.getIdMapping().put(initialId, e.getId());
});
}
//set file attributes
if (CollectionUtils.isNotEmpty(request.getFileAttributesConfigs())) {
request.getFileAttributesConfigs()
.forEach(fa -> {
String initialId = fa.getId();
fa.setId(null); // in order to force creation of new file attribute
var e = fileAttributeConfigPersistenceService.addOrUpdateFileAttribute(dossierTemplateId, convert(fa, FileAttributeConfigEntity.class));
templateImportInfo.getIdMapping().put(initialId, e.getId());
});
}
//set types
entityTypeImportService.importEntityTypes(dossierTemplateId, null, request.getEntityTypeImportModel());
// set components
if (CollectionUtils.isNotEmpty(request.getComponentDefinitions())) {
for (ComponentDefinition componentDefinition : request.getComponentDefinitions()) {
ComponentDefinitionAddRequest componentDefinitionAddRequest = ComponentDefinitionAddRequest.builder()
.displayName(componentDefinition.getDisplayName())
.description(componentDefinition.getDescription())
.technicalName(componentDefinition.getTechnicalName())
.build();
componentDefinitionPersistenceService.insert(componentDefinitionAddRequest, componentDefinition.getRank(), dossierTemplateId);
// dossier status
if (CollectionUtils.isNotEmpty(request.getDossierStatusInfos())) {
importStep = 4;
request.getDossierStatusInfos()
.forEach(state -> {
state.setId(null);
this.updateDossierStatus(dossierTemplateId, state);
});
}
//set dossier attributes
if (CollectionUtils.isNotEmpty(request.getDossierAttributesConfigs())) {
importStep = 5;
request.getDossierAttributesConfigs()
.forEach(da -> {
String initialId = da.getId();
da.setId(null); // in order to create a new dossier attribute
var e = dossierAttributeConfigPersistenceService.addOrUpdateDossierAttribute(dossierTemplateId, convert(da, DossierAttributeConfigEntity.class));
templateImportInfo.getIdMapping().put(initialId, e.getId());
});
}
//set file attributes
if (CollectionUtils.isNotEmpty(request.getFileAttributesConfigs())) {
importStep = 6;
request.getFileAttributesConfigs()
.forEach(fa -> {
String initialId = fa.getId();
fa.setId(null); // in order to force creation of new file attribute
var e = fileAttributeConfigPersistenceService.addOrUpdateFileAttribute(dossierTemplateId, convert(fa, FileAttributeConfigEntity.class));
templateImportInfo.getIdMapping().put(initialId, e.getId());
});
}
//set report templates
if (CollectionUtils.isNotEmpty(request.getReportTemplateUploadRequests())) {
importStep = 7;
request.getReportTemplateUploadRequests()
.forEach(reportRequest -> {
reportRequest.setDossierTemplateId(dossierTemplateId);
reportTemplateService.uploadTemplate(reportRequest);
});
}
// set legal basis
if (CollectionUtils.isNotEmpty(request.getLegalBases())) {
importStep = 8;
legalBasisMappingPersistenceService.setLegalBasisMapping(dossierTemplateId, request.getLegalBases());
}
// file attribute general configuration
if (request.getFileAttributesGeneralConfiguration() != null) {
importStep = 9;
fileAttributeConfigPersistenceService.setFileAttributesGeneralConfig(dossierTemplateId,
convert(request.getFileAttributesGeneralConfiguration(),
FileAttributesGeneralConfigurationEntity.class));
}
// set components
if (CollectionUtils.isNotEmpty(request.getComponentDefinitions())) {
importStep = 10;
for (ComponentDefinition componentDefinition : request.getComponentDefinitions()) {
ComponentDefinitionAddRequest componentDefinitionAddRequest = ComponentDefinitionAddRequest.builder()
.displayName(componentDefinition.getDisplayName())
.description(componentDefinition.getDescription())
.technicalName(componentDefinition.getTechnicalName())
.build();
componentDefinitionPersistenceService.insert(componentDefinitionAddRequest, componentDefinition.getRank(), dossierTemplateId);
}
}
//set component mappings
importStep = 11;
setComponentMappings(dossierTemplateId, request.getComponentMappings());
//set types
importStep = 12;
entityTypeImportService.importEntityTypes(dossierTemplateId, null, request.getEntityTypeImportModel());
}
//set report templates
if (CollectionUtils.isNotEmpty(request.getReportTemplateUploadRequests())) {
request.getReportTemplateUploadRequests()
.forEach(reportRequest -> {
reportRequest.setDossierTemplateId(dossierTemplateId);
reportTemplateService.uploadTemplate(reportRequest);
});
}
// set legal basis
if (CollectionUtils.isNotEmpty(request.getLegalBases())) {
legalBasisMappingPersistenceService.setLegalBasisMapping(dossierTemplateId, request.getLegalBases());
}
importStep = 13;
setRulesWhenCompiled(request, dossierTemplateId);
} catch (Exception e) {
throw new BadRequestException("The import process failed in step: " + importStep + " with error: " + e.getMessage());
}
// file attribute general configuration
if (request.getFileAttributesGeneralConfiguration() != null) {
fileAttributeConfigPersistenceService.setFileAttributesGeneralConfig(dossierTemplateId,
convert(request.getFileAttributesGeneralConfiguration(),
FileAttributesGeneralConfigurationEntity.class));
}
setRulesWhenCompiled(request, dossierTemplateId);
setComponentMappings(dossierTemplateId, request.getComponentMappings());
templateImportInfo.setDossierTemplateId(dossierTemplateId);
long elapsedTime = System.currentTimeMillis() - start;
@ -512,7 +563,7 @@ public class DossierTemplateImportService {
request.getFileAttributesConfigs()
.forEach(fa -> {
String initialId = fa.getId();
//check by id or by dossierTemplate and label and set the corresponding Id if found
//check by id or by dossierTemplate and label and set the corresponding id if found
fa.setId(fileAttributeConfigPersistenceService.getFileAttributeByIdOrName(dossierTemplateId, fa.getId(), fa.getLabel()));
FileAttributeConfigEntity fileAttributeAdded = fileAttributeConfigPersistenceService.addOrUpdateFileAttribute(dossierTemplateId,
convert(fa, FileAttributeConfigEntity.class));
@ -542,9 +593,7 @@ public class DossierTemplateImportService {
private void deleteComponents(List<ComponentDefinitionEntity> componentDefinitionEntities) {
componentDefinitionEntities.forEach(componentDefinition -> {
componentDefinitionPersistenceService.delete(componentDefinition.getId());
});
componentDefinitionEntities.forEach(componentDefinition -> componentDefinitionPersistenceService.delete(componentDefinition.getId()));
}

View File

@ -153,6 +153,7 @@ public class DossierTemplateImportTest extends AbstractPersistenceServerServiceT
var e = assertThrows(BadRequestException.class,
() -> dossierTemplateManagementService.importDossierTemplate(request));
assertThat(e.getMessage().contains("The import process failed in step: 13")).isTrue();
var reportTemplates = reportTemplateRepository.findAll();
assertThat(reportTemplates).hasSize(2);
var alldossierTemplates = dossierTemplateManagementService.getAllDossierTemplates();