Pull request #540: RED-2200 - Dossier Template export and import

Merge in RED/persistence-service from RED-2200_5 to master

* commit '870673f679ceaad22150eac0c00a43009c127668':
  RED-2200 - Dossier Template export and import
This commit is contained in:
Corina Olariu 2022-09-28 16:43:48 +02:00 committed by Timo Bejan
commit 618b5dc0bb
6 changed files with 106 additions and 39 deletions

View File

@ -72,9 +72,9 @@ public class DictionaryPersistenceService {
public void updateType(String typeId, TypeEntity typeValueRequest) { public void updateType(String typeId, TypeEntity typeValueRequest) {
typeRepository.findById(typeId).ifPresent(type -> { typeRepository.findById(typeId).ifPresent(type -> {
if (type.isDeleted()) { // if (type.isDeleted()) {
throw new NotFoundException("Type is deleted!"); // throw new NotFoundException("Type is deleted!");
} // }
type.setVersion(type.getVersion() + 1); type.setVersion(type.getVersion() + 1);
checkRankAlreadyExists(type.getType(), type.getDossierTemplate().getId(), typeValueRequest.getRank(), type.getDossier() == null ? null : type.getDossier().getId()); checkRankAlreadyExists(type.getType(), type.getDossierTemplate().getId(), typeValueRequest.getRank(), type.getDossier() == null ? null : type.getDossier().getId());
@ -223,4 +223,9 @@ public class DictionaryPersistenceService {
typeRepository.saveAll(types); typeRepository.saveAll(types);
} }
@Transactional
public int undeleteType(String typeId) {
return typeRepository.unSoftDeleteTypeById(typeId);
}
} }

View File

@ -48,4 +48,8 @@ public interface TypeRepository extends JpaRepository<TypeEntity, String> {
@Modifying(clearAutomatically = true, flushAutomatically = true) @Modifying(clearAutomatically = true, flushAutomatically = true)
@Query("Update TypeEntity t set t.softDeletedTime = CURRENT_TIMESTAMP where t.id = :typeId") @Query("Update TypeEntity t set t.softDeletedTime = CURRENT_TIMESTAMP where t.id = :typeId")
void softDeleteTypeById(String typeId); void softDeleteTypeById(String typeId);
@Modifying
@Query("Update TypeEntity t set t.softDeletedTime = null where t.id = :typeId and t.softDeletedTime is not null")
int unSoftDeleteTypeById(String typeId);
} }

View File

@ -21,6 +21,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.configur
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.TypeEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.TypeEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException; import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.ColorsService; import com.iqser.red.service.persistence.management.v1.processor.service.ColorsService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService;
@ -100,7 +101,7 @@ public class DictionaryService {
} }
// To check whether the type exists // To check whether the type exists and it is not deleted
Type typeResult = convert(dictionaryPersistenceService.getType(typeId), Type.class); Type typeResult = convert(dictionaryPersistenceService.getType(typeId), Type.class);
if (typeRequest.getLabel() != null) { if (typeRequest.getLabel() != null) {
@ -199,6 +200,17 @@ public class DictionaryService {
dictionaryPersistenceService.incrementVersion(typeId); dictionaryPersistenceService.incrementVersion(typeId);
} }
public long getCurrentVersion(String typeId) {
Type typeResult = convert(dictionaryPersistenceService.getType(typeId), Type.class);
long currentVersion;
if (typeResult.getDossierId() != null) {
currentVersion = dictionaryPersistenceService.getVersionForDossier(typeResult.getDossierId());
} else {
currentVersion = dictionaryPersistenceService.getVersion(typeResult.getDossierTemplateId());
}
return currentVersion;
}
private void validateBoolean(Boolean bool, String name) { private void validateBoolean(Boolean bool, String name) {
Optional<String> errorMessage = DictionaryValidator.validateBoolean(bool, name); Optional<String> errorMessage = DictionaryValidator.validateBoolean(bool, name);

View File

@ -118,14 +118,6 @@ public class DossierTemplateImportService {
configsToRemove.forEach(watermark -> watermarkService.deleteWatermark(watermark.getId())); configsToRemove.forEach(watermark -> watermarkService.deleteWatermark(watermark.getId()));
} }
// update the types
if (CollectionUtils.isNotEmpty(request.getTypes())) {
this.updateTypes(request, dossierTemplateId);
} else { // no types to add, but remove existing ones
List<TypeEntity> currentTypes = dossierTemplatePersistenceService.getDossierTemplate(dossierTemplateId).getDossierTypes();
currentTypes.forEach(type -> dictionaryService.deleteType(type.getId()));
}
// dossier status // dossier status
if (CollectionUtils.isNotEmpty(request.getDossierStatusInfos())) { if (CollectionUtils.isNotEmpty(request.getDossierStatusInfos())) {
this.updateDossierStates(request, dossierTemplateId); this.updateDossierStates(request, dossierTemplateId);
@ -150,12 +142,21 @@ public class DossierTemplateImportService {
currentConfigs.forEach(fa -> fileAttributeConfigPersistenceService.deleteFileAttribute(fa.getId())); currentConfigs.forEach(fa -> fileAttributeConfigPersistenceService.deleteFileAttribute(fa.getId()));
} }
// update the types
if (CollectionUtils.isNotEmpty(request.getTypes())) {
this.updateTypes(request, dossierTemplateId);
} else { // no types to add, but remove existing ones
List<TypeEntity> currentTypes = dossierTemplatePersistenceService.getDossierTemplate(dossierTemplateId).getDossierTypes()
.stream().filter(t -> t.getDossierId() == null).collect(Collectors.toList());
this.deleteTypes(currentTypes, new HashSet<>());
}
} else { } else {
// creates new dossier template // creates new dossier template
if (StringUtils.isEmpty(dossierTemplateMeta.getName())) { if (StringUtils.isEmpty(dossierTemplateMeta.getName())) {
throw new ConflictException("DossierTemplate name must be set"); throw new ConflictException("DossierTemplate name must be set");
} }
dossierTemplatePersistenceService.validateDossierTemplateNameIsUnique(dossierTemplateMeta.getName()); this.validateDossierTemplateName(dossierTemplateMeta);
DossierTemplateEntity dossierTemplateEntity = new DossierTemplateEntity(); DossierTemplateEntity dossierTemplateEntity = new DossierTemplateEntity();
// order is important // order is important
@ -181,17 +182,7 @@ public class DossierTemplateImportService {
}); });
} }
//set types
if (CollectionUtils.isNotEmpty(request.getTypes())) {
for (var type : request.getTypes()) {
type.setDossierTemplateId(dossierTemplateId);
var returnedType = dictionaryService.addType(type);
this.addEntries(request.getEntries(), returnedType.getTypeId(), returnedType.getType(), DictionaryEntryType.ENTRY);
this.addEntries(request.getFalsePositives(), returnedType.getTypeId(), returnedType.getType(), DictionaryEntryType.FALSE_POSITIVE);
this.addEntries(request.getFalseRecommendations(), returnedType.getTypeId(), returnedType.getType(), DictionaryEntryType.FALSE_RECOMMENDATION);
}
}
// dossier status // dossier status
if (CollectionUtils.isNotEmpty(request.getDossierStatusInfos())) { if (CollectionUtils.isNotEmpty(request.getDossierStatusInfos())) {
request.getDossierStatusInfos().forEach(state -> { request.getDossierStatusInfos().forEach(state -> {
@ -215,6 +206,18 @@ public class DossierTemplateImportService {
fileAttributeConfigPersistenceService.addOrUpdateFileAttribute(dossierTemplateId, convert(fa, FileAttributeConfigEntity.class)); fileAttributeConfigPersistenceService.addOrUpdateFileAttribute(dossierTemplateId, convert(fa, FileAttributeConfigEntity.class));
}); });
} }
//set types
if (CollectionUtils.isNotEmpty(request.getTypes())) {
for (var type : request.getTypes()) {
type.setDossierTemplateId(dossierTemplateId);
var returnedType = dictionaryService.addType(type);
this.addEntries(request.getEntries(), returnedType.getTypeId(), returnedType.getType(), DictionaryEntryType.ENTRY);
this.addEntries(request.getFalsePositives(), returnedType.getTypeId(), returnedType.getType(), DictionaryEntryType.FALSE_POSITIVE);
this.addEntries(request.getFalseRecommendations(), returnedType.getTypeId(), returnedType.getType(), DictionaryEntryType.FALSE_RECOMMENDATION);
}
}
} }
// set legal basis // set legal basis
if (CollectionUtils.isNotEmpty(request.getLegalBases())) { if (CollectionUtils.isNotEmpty(request.getLegalBases())) {
@ -289,8 +292,28 @@ public class DossierTemplateImportService {
return dossierStatusPersistenceService.createOrUpdateDossierStatus(dossierStatusRequest); return dossierStatusPersistenceService.createOrUpdateDossierStatus(dossierStatusRequest);
} }
private void validateDossierTemplateName(DossierTemplate dossierTemplateMeta) {
boolean cond = true;
int index = 0;
String dossierTemplateName = dossierTemplateMeta.getName();
do {
try {
dossierTemplatePersistenceService.validateDossierTemplateNameIsUnique(dossierTemplateMeta.getName());
cond = false;
} catch (ConflictException e) {
if (index == 0) {
dossierTemplateMeta.setName("Copy of " + dossierTemplateName);
} else {
dossierTemplateMeta.setName("Copy of " + dossierTemplateName + " - " + index);
}
index++;
}
} while (cond);
}
private void updateTypes(ImportTemplateResult request, String dossierTemplateId) { private void updateTypes(ImportTemplateResult request, String dossierTemplateId) {
List<TypeEntity> currentTypes = dossierTemplatePersistenceService.getDossierTemplate(dossierTemplateId).getDossierTypes(); List<TypeEntity> currentTypes = dossierTemplatePersistenceService.getDossierTemplate(dossierTemplateId).getDossierTypes()
.stream().filter(t -> t.getDossierId() == null).collect(Collectors.toList());
Set<String> currentTypesId = currentTypes.stream().map(TypeEntity::getId).collect(Collectors.toSet()); Set<String> currentTypesId = currentTypes.stream().map(TypeEntity::getId).collect(Collectors.toSet());
Set<String> typeIdsAdded = new HashSet<>(); Set<String> typeIdsAdded = new HashSet<>();
@ -301,9 +324,13 @@ public class DossierTemplateImportService {
String typeId; String typeId;
if (currentTypesId.contains(type.getId())) { //check by id if (currentTypesId.contains(type.getId())) { //check by id
typeId = type.getId(); typeId = type.getId();
// type found, possible to be deleted, undelete it first before updating
dictionaryPersistenceService.undeleteType(typeId);
dictionaryService.updateTypeValue(typeId, type); dictionaryService.updateTypeValue(typeId, type);
} else if (!typeToEntityMap.isEmpty() && typeToEntityMap.get(type.getType()) != null) { //check by name } else if (!typeToEntityMap.isEmpty() && typeToEntityMap.get(type.getType()) != null) { //check by name
typeId = typeToEntityMap.get(type.getType()).getId(); typeId = typeToEntityMap.get(type.getType()).getId();
// type found, possible to be deleted, undelete it first before updating
dictionaryPersistenceService.undeleteType(typeId);
dictionaryService.updateTypeValue(typeId, type); dictionaryService.updateTypeValue(typeId, type);
} else { // add the type, no match was found } else { // add the type, no match was found
var returnedType = dictionaryService.addType(type); var returnedType = dictionaryService.addType(type);
@ -315,11 +342,26 @@ public class DossierTemplateImportService {
this.addEntries(request.getFalsePositives(), typeId, type.getTypeId(), DictionaryEntryType.FALSE_POSITIVE); this.addEntries(request.getFalsePositives(), typeId, type.getTypeId(), DictionaryEntryType.FALSE_POSITIVE);
this.addEntries(request.getFalseRecommendations(), typeId, type.getTypeId(), DictionaryEntryType.FALSE_RECOMMENDATION); this.addEntries(request.getFalseRecommendations(), typeId, type.getTypeId(), DictionaryEntryType.FALSE_RECOMMENDATION);
} }
// remove additional types // remove additional types and not included in the archive
Set<String> typesToRemove = currentTypesId.stream().filter(t -> !typeIdsAdded.contains(t)).collect(Collectors.toSet()); this.deleteTypes(currentTypes, typeIdsAdded);
typesToRemove.forEach(dictionaryService::deleteType);
} }
private void deleteTypes(List<TypeEntity> currentTypes, Set<String> typeIdsAdded) {
Set<String> currentTypesIdSystemManaged = currentTypes.stream().filter(TypeEntity::isSystemManaged).map(TypeEntity::getId).collect(Collectors.toSet());
// for types system managed just delete the entries
Set<String> entriesToRemove = currentTypesIdSystemManaged.stream().filter(t -> !typeIdsAdded.contains(t)).collect(Collectors.toSet());
entriesToRemove.forEach(typeId -> {
var currentVersion = dictionaryService.getCurrentVersion(typeId);
entryPersistenceService.deleteAllEntriesForTypeId(typeId, currentVersion + 1, DictionaryEntryType.ENTRY);
entryPersistenceService.deleteAllEntriesForTypeId(typeId, currentVersion + 1, DictionaryEntryType.FALSE_POSITIVE);
entryPersistenceService.deleteAllEntriesForTypeId(typeId, currentVersion + 1, DictionaryEntryType.FALSE_RECOMMENDATION);
dictionaryPersistenceService.incrementVersion(typeId);
typeIdsAdded.add(typeId); // added to the list, since the type can not be deleted
});
Set<String> typesToRemove = currentTypes.stream().map(TypeEntity::getId).filter(t -> !typeIdsAdded.contains(t)).collect(Collectors.toSet());
typesToRemove.forEach(dictionaryService::deleteType);
}
private void updateDossierStates(ImportTemplateResult request, String dossierTemplateId) { private void updateDossierStates(ImportTemplateResult request, String dossierTemplateId) {
List<DossierStatusInfo> currentStates = dossierStatusPersistenceService.getAllDossierStatusForTemplate(dossierTemplateId); List<DossierStatusInfo> currentStates = dossierStatusPersistenceService.getAllDossierStatusForTemplate(dossierTemplateId);
@ -358,7 +400,7 @@ public class DossierTemplateImportService {
}); });
// remove existing dossier attributes and not included in archive // remove existing dossier attributes and not included in archive
Set<String> attributesToRemove = currentDossierAttributeIds.stream().filter(da -> !dossierAttributeIdsAdded.contains(da)).collect(Collectors.toSet()); Set<String> attributesToRemove = currentDossierAttributeIds.stream().filter(da -> !dossierAttributeIdsAdded.contains(da)).collect(Collectors.toSet());
attributesToRemove.forEach(daId -> dossierAttributeConfigPersistenceService.deleteDossierAttribute(daId)); attributesToRemove.forEach(dossierAttributeConfigPersistenceService::deleteDossierAttribute);
} }
private void updateFileAttributes(ImportTemplateResult request, String dossierTemplateId) { private void updateFileAttributes(ImportTemplateResult request, String dossierTemplateId) {
@ -373,7 +415,7 @@ public class DossierTemplateImportService {
}); });
// remove existing file attributes and not included in archive // remove existing file attributes and not included in archive
Set<String> attributesToRemove = currentFileAttributeIds.stream().filter(fa -> !fileAttributeIdsAdded.contains(fa)).collect(Collectors.toSet()); Set<String> attributesToRemove = currentFileAttributeIds.stream().filter(fa -> !fileAttributeIdsAdded.contains(fa)).collect(Collectors.toSet());
attributesToRemove.forEach(faId -> fileAttributeConfigPersistenceService.deleteFileAttribute(faId)); attributesToRemove.forEach(fileAttributeConfigPersistenceService::deleteFileAttribute);
} }
public ImportTemplateResult handleArchive(ImportDossierTemplateRequest request) { public ImportTemplateResult handleArchive(ImportDossierTemplateRequest request) {
@ -474,17 +516,17 @@ public class DossierTemplateImportService {
} else if (ze.getName().contains(ExportFilename.ENTRIES.getFilename())) { } else if (ze.getName().contains(ExportFilename.ENTRIES.getFilename())) {
List<String> entries = this.readEntries(bytes); List<String> entries = this.readEntries(bytes);
typeEntriesMap.put(this.getTypeId(ze.getName()), entries); typeEntriesMap.put(this.getType(ze.getName()), entries);
} else if (ze.getName().contains(ExportFilename.FALSE_POSITIVES.getFilename())) { } else if (ze.getName().contains(ExportFilename.FALSE_POSITIVES.getFilename())) {
List<String> falsePositives = this.readEntries(bytes); List<String> falsePositives = this.readEntries(bytes);
typeFalsePositivesMap.put(this.getTypeId(ze.getName()), falsePositives); typeFalsePositivesMap.put(this.getType(ze.getName()), falsePositives);
} else if (ze.getName().contains(ExportFilename.FALSE_RECOMMENDATION.getFilename())) { } else if (ze.getName().contains(ExportFilename.FALSE_RECOMMENDATION.getFilename())) {
List<String> falseRecommendations = this.readEntries(bytes); List<String> falseRecommendations = this.readEntries(bytes);
typeFalseRecommendationsMap.put(this.getTypeId(ze.getName()), falseRecommendations); typeFalseRecommendationsMap.put(this.getType(ze.getName()), falseRecommendations);
} else if (ze.getName().contains(ExportFilename.REPORT_TEMPLATE.getFilename())) { } else if (ze.getName().contains(ExportFilename.REPORT_TEMPLATE.getFilename())) {
var reportTemplateList = objectMapper.readValue(bytes, new TypeReference<List<ReportTemplate>>() { var reportTemplateList = objectMapper.readValue(bytes, new TypeReference<List<ReportTemplate>>() {
@ -554,7 +596,7 @@ public class DossierTemplateImportService {
return entries; return entries;
} }
private String getTypeId(String filename) { private String getType(String filename) {
var index = filename.indexOf('/'); var index = filename.indexOf('/');
return filename.substring(0, index); return filename.substring(0, index);
} }

View File

@ -139,10 +139,14 @@ public class DossierTemplateExportService {
// for every type 1 folder with: // for every type 1 folder with:
// 1 json file containing meta info of the type // 1 json file containing meta info of the type
// and 1 txt file for every type: entries, false positives and false recommendation // and 1 txt file for every type: entries, false positives and false recommendation
var dossierTypes = dossierTemplate.getDossierTypes();
// remove the types related to dossiers and also the ones that are deleted
var dossierTypes = dossierTemplate.getDossierTypes().stream()
.filter(t -> t.getDossierId() == null)
.filter(t -> !t.isDeleted()).collect(Collectors.toList());
for (TypeEntity typeEntity : dossierTypes) { for (TypeEntity typeEntity : dossierTypes) {
// log.info("type: " + typeEntity.getType() + " " + typeEntity.getDossierId()); // log.info("type: " + typeEntity.getType() + " " + typeEntity.getDossierId() + " " + typeEntity.isDeleted());
fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(typeEntity.getId(), getFilename(ExportFilename.DOSSIER_TYPE, JSON_EXT), fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(typeEntity.getType(), getFilename(ExportFilename.DOSSIER_TYPE, JSON_EXT),
objectMapper.writeValueAsBytes(convert(typeEntity, Type.class)))); objectMapper.writeValueAsBytes(convert(typeEntity, Type.class))));
var entriesValuesList = entryPersistenceService.getEntries(typeEntity.getId(), DictionaryEntryType.ENTRY, null) var entriesValuesList = entryPersistenceService.getEntries(typeEntity.getId(), DictionaryEntryType.ENTRY, null)

View File

@ -56,7 +56,7 @@ public class DownloadCleanupJob implements Job {
log.info("2. Deleting download status {} because DownloadCleanupNotDownloadFilesHours is {} and c+h {} is after {}", downloadStatus, applicationConfigurationEntity.getDownloadCleanupNotDownloadFilesHours(), downloadStatus.getCreationDate() log.info("2. Deleting download status {} because DownloadCleanupNotDownloadFilesHours is {} and c+h {} is after {}", downloadStatus, applicationConfigurationEntity.getDownloadCleanupNotDownloadFilesHours(), downloadStatus.getCreationDate()
.plusHours(applicationConfigurationEntity.getDownloadCleanupNotDownloadFilesHours()), now); .plusHours(applicationConfigurationEntity.getDownloadCleanupNotDownloadFilesHours()), now);
deleteDownload(downloadStatus); deleteDownload(downloadStatus);
} else if (dossierService.getDossierById(dossier.getId()).getSoftDeletedTime() != null) { } else if (dossier != null && dossierService.getDossierById(dossier.getId()).getSoftDeletedTime() != null) {
log.info("3. Deleting download {}, because dossier does not exist", downloadStatus.getStorageId()); log.info("3. Deleting download {}, because dossier does not exist", downloadStatus.getStorageId());
deleteDownload(downloadStatus); deleteDownload(downloadStatus);
} }