diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java index 3e5095fc6..03f71ed61 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java @@ -40,6 +40,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RemoveRedactionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ResizeRedactionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequestModel; @@ -238,7 +239,7 @@ public class ManualRedactionController implements ManualRedactionResource { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsMemberOrApprover(dossierId); - List requests = manualRedactionMapper.toForceRedactionRequestList(forceRedactionRequests); + List requests = manualRedactionMapper.toForceRedactionRequestList(dossierId, fileId, forceRedactionRequests); List responseList = manualRedactionService.addForceRedaction(dossierId, fileId, requests); responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder() @@ -263,7 +264,7 @@ public class ManualRedactionController implements ManualRedactionResource { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsMemberOrApprover(dossierId); - List requests = manualRedactionMapper.toLegalBasisChangeRequestList(legalBasisChangeRequests); + List requests = manualRedactionMapper.toLegalBasisChangeRequestList(dossierId, fileId, legalBasisChangeRequests); List responseList = manualRedactionService.addLegalBasisChange(dossierId, fileId, requests); @@ -320,7 +321,7 @@ public class ManualRedactionController implements ManualRedactionResource { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsMemberOrApprover(dossierId); - List requests = manualRedactionMapper.toResizeRedactionRequestList(resizeRedactionRequests); + List requests = manualRedactionMapper.toResizeRedactionRequestList(dossierId, fileId, resizeRedactionRequests, includeUnprocessed); List responseList = manualRedactionService.addResizeRedaction(dossierId, fileId, requests, includeUnprocessed); responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder() diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/annotations/ManualRecategorizationEntity.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/annotations/ManualRecategorizationEntity.java index 92595e1ca..210addf02 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/annotations/ManualRecategorizationEntity.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/annotations/ManualRecategorizationEntity.java @@ -51,6 +51,8 @@ public class ManualRecategorizationEntity implements IBaseAnnotation { private String legalBasis; @Column(length = 1024) private String section; + @Column + private String value; @ManyToOne private FileEntity fileStatus; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMergeService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMergeService.java index a148946f7..bfd679a24 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMergeService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMergeService.java @@ -4,6 +4,7 @@ import static com.iqser.red.service.persistence.management.v1.processor.utils.Ty import java.time.OffsetDateTime; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -13,7 +14,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -97,11 +97,15 @@ public class EntityLogMergeService { if (allManualChanges.containsKey(entityLogEntry.getId())) { - mergeLocalManualChanges(dossier, allManualChanges, entityLogEntry, analysisNumber); + List pendingImageRecategorizations = mergeLocalManualChangesAndReturnNonMergeableAsPending(dossier, + allManualChanges, + entityLogEntry, + analysisNumber); List pendingDictionaryEntries = buildPendingDictionaryEntries(allManualChanges, entityLogEntry); + // insert pending entries directly after the associated entry to enable performant linking in UI - for (EntityLogEntry pendingDictionaryEntry : pendingDictionaryEntries) { + for (EntityLogEntry pendingDictionaryEntry : concatLists(pendingDictionaryEntries, pendingImageRecategorizations)) { numberOfAddedPendingEntries++; entityLogEntries.add(i + numberOfAddedPendingEntries, pendingDictionaryEntry); } @@ -117,6 +121,14 @@ public class EntityLogMergeService { } + private static List concatLists(List pendingDictionaryEntries, List pendingImageRecategorizations) { + + return Stream.of(pendingDictionaryEntries, pendingImageRecategorizations) + .flatMap(Collection::stream) + .toList(); + } + + private Stream buildPendingDictionaryChanges(ManualRedactions unprocessedManualRedactions) { return unprocessedManualRedactions.getEntriesToAdd() @@ -161,25 +173,36 @@ public class EntityLogMergeService { } - private void mergeLocalManualChanges(DossierEntity dossier, Map> allManualChanges, EntityLogEntry entityLogEntry, int analysisNumber) { + private List mergeLocalManualChangesAndReturnNonMergeableAsPending(DossierEntity dossier, + Map> allManualChanges, + EntityLogEntry entityLogEntry, + int analysisNumber) { - allManualChanges.getOrDefault(entityLogEntry.getId(), Collections.emptyList()) + return allManualChanges.getOrDefault(entityLogEntry.getId(), Collections.emptyList()) .stream() .filter(BaseAnnotation::isLocal) .sorted(Comparator.comparing(BaseAnnotation::getRequestDate)) - .forEach(localChange -> { + .map(localChange -> { if (localChange instanceof IdRemoval idRemoval) { - mergeIdsToRemove(idRemoval, entityLogEntry, analysisNumber); + mergeIdToRemove(idRemoval, entityLogEntry, analysisNumber); + return null; } else if (localChange instanceof ManualResizeRedaction manualResizeRedaction) { - mergeResizeRedactions(manualResizeRedaction, entityLogEntry, analysisNumber); + mergeResizeRedaction(manualResizeRedaction, entityLogEntry, analysisNumber); + return null; } else if (localChange instanceof ManualLegalBasisChange manualLegalBasisChange) { - mergeLegalBasisChanges(manualLegalBasisChange, entityLogEntry, analysisNumber); + mergeLegalBasisChange(manualLegalBasisChange, entityLogEntry, analysisNumber); + return null; } else if (localChange instanceof ManualRecategorization manualRecategorization) { - mergeRecategorizations(manualRecategorization, entityLogEntry, dossier, analysisNumber); + return mergeRecategorization(manualRecategorization, entityLogEntry, dossier, analysisNumber); } else if (localChange instanceof ManualForceRedaction manualForceRedaction) { - mergeForceRedactions(manualForceRedaction, entityLogEntry, analysisNumber); + mergeForceRedaction(manualForceRedaction, entityLogEntry, analysisNumber); + return null; + } else { + return null; } - }); + }) + .filter(Objects::nonNull) + .toList(); } @@ -211,7 +234,8 @@ public class EntityLogMergeService { .build()); List changes = new ArrayList<>(); - changes.add(Change.builder().analysisNumber(entityLog.getAnalysisNumber()).dateTime(manualRedactionEntry.getRequestDate()).type(ChangeType.ADDED).build()); + changes.add(Change.builder().analysisNumber(entityLog.getAnalysisNumber()).dateTime(manualRedactionEntry.getRequestDate()).type(ChangeType.ADDED) + .build()); boolean isHint = isHint(manualRedactionEntry.getType(), dossier); @@ -235,7 +259,7 @@ public class EntityLogMergeService { .excluded(false) .changes(changes) .manualChanges(manualChanges) - .engines(Set.of(Engine.MANUAL)) + .engines(new HashSet<>(List.of(Engine.MANUAL))) .reference(new HashSet<>()) .importedRedactionIntersections(new HashSet<>()) .containingNodeId(Collections.emptyList()) @@ -259,7 +283,8 @@ public class EntityLogMergeService { existingEntry.setState(EntryState.REMOVED); List falsePositiveChanges = new ArrayList<>(); - falsePositiveChanges.add(Change.builder().analysisNumber(entityLog.getAnalysisNumber()).dateTime(OffsetDateTime.now()).type(ChangeType.REMOVED).build()); + falsePositiveChanges.add(Change.builder().analysisNumber(entityLog.getAnalysisNumber()).dateTime(OffsetDateTime.now()).type(ChangeType.REMOVED) + .build()); if (existingEntry.getChanges() != null && !existingEntry.getChanges().isEmpty()) { existingEntry.getChanges().addAll(falsePositiveChanges); } else { @@ -268,7 +293,7 @@ public class EntityLogMergeService { } - private void mergeIdsToRemove(IdRemoval idRemoval, EntityLogEntry entityLogEntry, int analysisNumber) { + private void mergeIdToRemove(IdRemoval idRemoval, EntityLogEntry entityLogEntry, int analysisNumber) { entityLogEntry.setState(EntryState.IGNORED); entityLogEntry.getEngines().add(Engine.MANUAL); @@ -285,7 +310,7 @@ public class EntityLogMergeService { } - private void mergeResizeRedactions(ManualResizeRedaction manualResizeRedaction, EntityLogEntry entityLogEntry, int analysisNumber) { + private void mergeResizeRedaction(ManualResizeRedaction manualResizeRedaction, EntityLogEntry entityLogEntry, int analysisNumber) { entityLogEntry.setTextAfter(manualResizeRedaction.getTextAfter()); entityLogEntry.setTextBefore(manualResizeRedaction.getTextBefore()); @@ -302,10 +327,16 @@ public class EntityLogMergeService { manualChange.propertyChanges(Map.of("value", manualResizeRedaction.getValue())); } entityLogEntry.getManualChanges().add(manualChange.build()); + + if ((entityLogEntry.isDictionaryEntry() || entityLogEntry.isDossierDictionaryEntry()) + && !manualResizeRedaction.getUpdateDictionary() + && !manualResizeRedaction.isAddToAllDossiers()) { + entityLogEntry.setState(EntryState.REMOVED); + } } - private void mergeLegalBasisChanges(ManualLegalBasisChange manualLegalBasisChange, EntityLogEntry entityLogEntry, int analysisNumber) { + private void mergeLegalBasisChange(ManualLegalBasisChange manualLegalBasisChange, EntityLogEntry entityLogEntry, int analysisNumber) { entityLogEntry.setLegalBasis(manualLegalBasisChange.getLegalBasis()); entityLogEntry.setSection(manualLegalBasisChange.getSection()); @@ -322,6 +353,9 @@ public class EntityLogMergeService { .userId(manualLegalBasisChange.getUser()) .build()); + if (entityLogEntry.isDictionaryEntry() || entityLogEntry.isDossierDictionaryEntry()) { + entityLogEntry.setState(EntryState.REMOVED); + } } @@ -341,14 +375,39 @@ public class EntityLogMergeService { } - private void mergeRecategorizations(ManualRecategorization recategorization, EntityLogEntry entityLogEntry, DossierEntity dossier, int analysisNumber) { + private EntityLogEntry mergeRecategorization(ManualRecategorization recategorization, EntityLogEntry entityLogEntry, DossierEntity dossier, int analysisNumber) { + + if (entityLogEntry.getEntryType().equals(EntryType.IMAGE) || entityLogEntry.getEntryType().equals(EntryType.IMAGE_HINT)) { + return pendingDictionaryEntryFactory.buildPendingImageRecategorizationEntry(recategorization, entityLogEntry); + } boolean isHint = isHint(recategorization.getType(), dossier); - entityLogEntry.setType(recategorization.getType()); + if (!Strings.isNullOrEmpty(recategorization.getType())) { + entityLogEntry.setType(recategorization.getType()); + } + entityLogEntry.setEntryType(getEntryType(isHint, recategorization.getType())); - entityLogEntry.setState(isHint ? EntryState.SKIPPED : EntryState.APPLIED); + + entityLogEntry.setState(isHint ? EntryState.SKIPPED : EntryState.APPLIED); // TODO: only set applied if legalBasis is set by recategorization + entityLogEntry.getEngines().add(Engine.MANUAL); + + if (!Strings.isNullOrEmpty(recategorization.getLegalBasis())) { + entityLogEntry.setLegalBasis(recategorization.getLegalBasis()); + entityLogEntry.setState(isHint ? EntryState.SKIPPED : EntryState.APPLIED); + } else { + entityLogEntry.setState(EntryState.SKIPPED); + } + + if (!Strings.isNullOrEmpty(recategorization.getSection())) { + entityLogEntry.setSection(recategorization.getSection()); + } + + if (!Strings.isNullOrEmpty(recategorization.getValue())) { + entityLogEntry.setValue(recategorization.getValue()); + } + addChanges(entityLogEntry.getChanges(), ChangeType.CHANGED, analysisNumber, recategorization.getRequestDate()); entityLogEntry.getManualChanges() .add(ManualChange.builder() @@ -358,10 +417,15 @@ public class EntityLogMergeService { .userId(recategorization.getUser()) .propertyChanges(getPropertyChanges(recategorization)) .build()); + + if ((entityLogEntry.isDictionaryEntry() || entityLogEntry.isDossierDictionaryEntry()) && !recategorization.isAddToDictionary() && !recategorization.isAddToAllDossiers()) { + entityLogEntry.setState(EntryState.REMOVED); + } + return null; } - private Map getPropertyChanges(ManualRecategorization recategorization) { + public static Map getPropertyChanges(ManualRecategorization recategorization) { Map propertyChanges = new HashMap<>(); if (!Strings.isNullOrEmpty(recategorization.getType())) { @@ -373,11 +437,14 @@ public class EntityLogMergeService { if (!Strings.isNullOrEmpty(recategorization.getSection())) { propertyChanges.put("section", recategorization.getSection()); } + if (!Strings.isNullOrEmpty(recategorization.getValue())) { + propertyChanges.put("value", recategorization.getValue()); + } return propertyChanges; } - private void mergeForceRedactions(ManualForceRedaction forceRedaction, EntityLogEntry entityLogEntry, int analysisNumber) { + private void mergeForceRedaction(ManualForceRedaction forceRedaction, EntityLogEntry entityLogEntry, int analysisNumber) { entityLogEntry.setLegalBasis(forceRedaction.getLegalBasis()); entityLogEntry.setState(entityLogEntry.getEntryType().equals(EntryType.HINT) ? EntryState.SKIPPED : EntryState.APPLIED); @@ -393,6 +460,9 @@ public class EntityLogMergeService { } entityLogEntry.getManualChanges().add(forceRedactManualChange.build()); + if (entityLogEntry.isDictionaryEntry() || entityLogEntry.isDossierDictionaryEntry()) { + entityLogEntry.setState(EntryState.REMOVED); + } } @@ -409,9 +479,11 @@ public class EntityLogMergeService { private void addChanges(List changes, ChangeType changeType, int analysisNumber, OffsetDateTime offsetDateTime) { if (!changes.isEmpty()) { - changes.add(Change.builder().analysisNumber(analysisNumber + 1).dateTime(offsetDateTime).type(changeType).build()); + changes.add(Change.builder().analysisNumber(analysisNumber + 1).dateTime(offsetDateTime).type(changeType) + .build()); } else { - changes.add(Change.builder().analysisNumber(analysisNumber).dateTime(OffsetDateTime.now()).type(changeType).build()); + changes.add(Change.builder().analysisNumber(analysisNumber).dateTime(OffsetDateTime.now()).type(changeType) + .build()); } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionDictionaryUpdateHandler.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionDictionaryUpdateHandler.java index 224b3b4e5..945fee559 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionDictionaryUpdateHandler.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionDictionaryUpdateHandler.java @@ -52,7 +52,7 @@ public class ManualRedactionDictionaryUpdateHandler { public Set handleAddToDictionaryAndReturnModifiedTypeIds(String fileId, String value, ManualRequestWithAddToDictionary manualRequestWithAddToDictionary) { - if (!manualRequestWithAddToDictionary.isAddToDictionary()) { + if (!manualRequestWithAddToDictionary.isAddToDictionary() || value == null) { return Collections.emptySet(); } Set typeIdsOfModifiedDictionaries = new HashSet<>(); @@ -99,7 +99,7 @@ public class ManualRedactionDictionaryUpdateHandler { public Set handleRemoveFromDictionaryAndReturnModifiedTypeIds(String fileId, ManualRequestWithRemoveFromDictionary manualRequestWithRemoveFromDictionary) { - if (!manualRequestWithRemoveFromDictionary.isRemoveFromDictionary()) { + if (!manualRequestWithRemoveFromDictionary.isRemoveFromDictionary() || manualRequestWithRemoveFromDictionary.getValue() == null) { return Collections.emptySet(); } String dossierId = manualRequestWithRemoveFromDictionary.getDossierId(); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionMapper.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionMapper.java index 241b29270..8f2c9beb7 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionMapper.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionMapper.java @@ -2,6 +2,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service.manual import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -9,18 +10,21 @@ import java.util.Set; import org.springframework.stereotype.Service; -import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Engine; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ForceRedactionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.LegalBasisChangeRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RecategorizationRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RemoveRedactionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ResizeRedactionRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRedactionEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel; @@ -42,6 +46,7 @@ import lombok.experimental.FieldDefaults; public class ManualRedactionMapper { EntityLogService entityLogService; + ManualRedactionService manualRedactionService; @Observed(name = "ManualRedactionMapper", contextualName = "to-add-redaction-request-list") @@ -84,6 +89,7 @@ public class ManualRedactionMapper { List requests = new ArrayList<>(); EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId, includeUnprocessed); for (var removeRedactionRequest : removeRedactionRequests) { + EntityLogEntry entityLogEntry = getEntityLogEntry(entityLog, removeRedactionRequest.getAnnotationId()); var removeRedactionRequestBuilder = RemoveRedactionRequest.builder() .annotationId(removeRedactionRequest.getAnnotationId()) @@ -102,36 +108,63 @@ public class ManualRedactionMapper { requests.add(removeRedactionRequestBuilder.build()); } + return requests; } - public List toForceRedactionRequestList(Set forceRedactionRequests) { + public List toForceRedactionRequestList(String dossierId, String fileId, Set forceRedactionRequests) { - return forceRedactionRequests.stream() - .map(forceRedactionRequest -> ForceRedactionRequest.builder() - .annotationId(forceRedactionRequest.getAnnotationId()) - .user(KeycloakSecurity.getUserId()) - .legalBasis(forceRedactionRequest.getLegalBasis()) - .comment(forceRedactionRequest.getComment()) - .build()) - .toList(); + EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId, Collections.emptyList(), true); + List requests = new ArrayList<>(); + + for (ForceRedactionRequestModel forceRedactionRequestModel : forceRedactionRequests) { + + EntityLogEntry entityLogEntry = getEntityLogEntry(entityLog, forceRedactionRequestModel.getAnnotationId()); + ForceRedactionRequest forceRedactionRequest = ForceRedactionRequest.builder() + .annotationId(forceRedactionRequestModel.getAnnotationId()) + .user(KeycloakSecurity.getUserId()) + .legalBasis(forceRedactionRequestModel.getLegalBasis()) + .comment(forceRedactionRequestModel.getComment()) + .build(); + + if (!entityLogEntry.getEngines().contains(Engine.MANUAL)) { + addManualRedactionEntry(fileId, entityLogEntry); + } + + requests.add(forceRedactionRequest); + } + + return requests; } @Deprecated(forRemoval = true) - public List toLegalBasisChangeRequestList(Set legalBasisChangeRequests) { + public List toLegalBasisChangeRequestList(String dossierId, String fileId, Set legalBasisChangeRequests) { - return legalBasisChangeRequests.stream() - .map(legalBasisChangeRequest -> LegalBasisChangeRequest.builder() - .annotationId(legalBasisChangeRequest.getAnnotationId()) - .user(KeycloakSecurity.getUserId()) - .section(legalBasisChangeRequest.getSection()) - .legalBasis(legalBasisChangeRequest.getLegalBasis()) - .comment(legalBasisChangeRequest.getComment()) - .value(legalBasisChangeRequest.getValue()) - .build()) - .toList(); + EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId, Collections.emptyList(), true); + List requests = new ArrayList<>(); + + for (LegalBasisChangeRequestModel legalBasisChangeRequest : legalBasisChangeRequests) { + + EntityLogEntry entityLogEntry = getEntityLogEntry(entityLog, legalBasisChangeRequest.getAnnotationId()); + LegalBasisChangeRequest request = LegalBasisChangeRequest.builder() + .annotationId(legalBasisChangeRequest.getAnnotationId()) + .user(KeycloakSecurity.getUserId()) + .section(legalBasisChangeRequest.getSection()) + .legalBasis(legalBasisChangeRequest.getLegalBasis()) + .comment(legalBasisChangeRequest.getComment()) + .value(legalBasisChangeRequest.getValue()) + .build(); + + if (!entityLogEntry.getEngines().contains(Engine.MANUAL)) { + addManualRedactionEntry(fileId, entityLogEntry); + } + + requests.add(request); + } + + return requests; } @@ -143,9 +176,11 @@ public class ManualRedactionMapper { EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId, includeUnprocessed); List requests = new ArrayList<>(); + for (RecategorizationRequestModel recategorizationRequest : recategorizationRequests) { + EntityLogEntry entityLogEntry = getEntityLogEntry(entityLog, recategorizationRequest.getAnnotationId()); - RecategorizationRequest build = RecategorizationRequest.builder() + RecategorizationRequest request = RecategorizationRequest.builder() .annotationId(recategorizationRequest.getAnnotationId()) .user(KeycloakSecurity.getUserId()) .dossierTemplateId(dossierTemplateId) @@ -154,33 +189,54 @@ public class ManualRedactionMapper { .addToDictionary(recategorizationRequest.isAddToDictionary()) .addToAllDossiers(recategorizationRequest.isAddToAllDossiers()) .dictionaryEntryType(getDictionaryEntryType(entityLogEntry)) - .value(entityLogEntry.getValue()) + .value(recategorizationRequest.getValue()) .typeToRemove(entityLogEntry.getType()) .dossierTemplateTypeId(toTypeId(recategorizationRequest.getType(), dossierTemplateId)) .legalBasis(Optional.ofNullable(recategorizationRequest.getLegalBasis()) .orElse("")) .section(recategorizationRequest.getSection()) .build(); - requests.add(build); + + if (!entityLogEntry.getEngines().contains(Engine.MANUAL) && !recategorizationRequest.isAddToAllDossiers() && !recategorizationRequest.isAddToDictionary()) { + addManualRedactionEntry(fileId, entityLogEntry); + } + + requests.add(request); } return requests; } - public List toResizeRedactionRequestList(Set resizeRedactionRequests) { + public List toResizeRedactionRequestList(String dossierId, + String fileId, + Set resizeRedactionRequests, + boolean includeUnprocessed) { - return resizeRedactionRequests.stream() - .map(resizeRedactionRequest -> ResizeRedactionRequest.builder() - .annotationId(resizeRedactionRequest.getAnnotationId()) - .user(KeycloakSecurity.getUserId()) - .positions(resizeRedactionRequest.getPositions()) - .value(resizeRedactionRequest.getValue() == null ? "" : StringCleaningUtility.cleanString(resizeRedactionRequest.getValue())) - .comment(resizeRedactionRequest.getComment()) - .updateDictionary(resizeRedactionRequest.getUpdateDictionary()) - .addToAllDossiers(resizeRedactionRequest.isAddToAllDossiers()) - .build()) - .toList(); + EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId, Collections.emptyList(), includeUnprocessed); + List requests = new ArrayList<>(); + + for (ResizeRedactionRequestModel resizeRedactionRequest : resizeRedactionRequests) { + + EntityLogEntry entityLogEntry = getEntityLogEntry(entityLog, resizeRedactionRequest.getAnnotationId()); + ResizeRedactionRequest request = ResizeRedactionRequest.builder() + .annotationId(resizeRedactionRequest.getAnnotationId()) + .user(KeycloakSecurity.getUserId()) + .positions(resizeRedactionRequest.getPositions()) + .value(resizeRedactionRequest.getValue() == null ? "" : StringCleaningUtility.cleanString(resizeRedactionRequest.getValue())) + .comment(resizeRedactionRequest.getComment()) + .updateDictionary(resizeRedactionRequest.getUpdateDictionary()) + .addToAllDossiers(resizeRedactionRequest.isAddToAllDossiers()) + .build(); + + if (!entityLogEntry.getEngines().contains(Engine.MANUAL) && !request.isAddToAllDossiers() && !request.getUpdateDictionary()) { + addManualRedactionEntry(fileId, entityLogEntry); + } + + requests.add(request); + } + + return requests; } @@ -205,4 +261,51 @@ public class ManualRedactionMapper { } } + + private void addManualRedactionEntry(String fileId, EntityLogEntry entityLogEntry) { + + ManualRedactionEntry manualRedactionEntry = ManualRedactionEntry.builder() + .value(entityLogEntry.getValue()) + .reason(entityLogEntry.getReason()) + .section(entityLogEntry.getSection()) + .annotationId(entityLogEntry.getId()) + .type(entityLogEntry.getType()) + .addToDossierDictionary(false) + .addToDictionary(false) + .positions(convertPositions(entityLogEntry.getPositions())) + .rectangle(entityLogEntry.getEntryType() == EntryType.AREA) + .user(KeycloakSecurity.getUserId()) + .legalBasis(entityLogEntry.getLegalBasis()) + .textAfter(entityLogEntry.getTextAfter()) + .textBefore(entityLogEntry.getTextBefore()) + .dictionaryEntryType(convertEntryType(entityLogEntry)) + .fileId(fileId) + .requestDate(OffsetDateTime.now()) + .build(); + + manualRedactionService.addManualRedactionEntries(List.of(manualRedactionEntry), false); + } + + + private List convertPositions(List positions) { + + return positions.stream() + .map(rectangle -> new Rectangle(rectangle.x(), rectangle.y(), rectangle.w(), rectangle.h(), rectangle.getPageNumber())) + .toList(); + } + + + private DictionaryEntryType convertEntryType(EntityLogEntry entityLogEntry) { + + if (entityLogEntry.getEntryType().equals(EntryType.FALSE_POSITIVE)) { + return DictionaryEntryType.FALSE_POSITIVE; + } + + if (entityLogEntry.getEntryType().equals(EntryType.FALSE_RECOMMENDATION)) { + return DictionaryEntryType.FALSE_RECOMMENDATION; + } + + return DictionaryEntryType.ENTRY; + } + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java index b1fafbed7..542d16edf 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java @@ -239,6 +239,7 @@ public class ManualRedactionService { Set typeIdsOfDictionariesWithAdd = manualRedactionDictionaryUpdateHandler.handleAddToDictionaryAndReturnModifiedTypeIds(fileId, recategorizationRequest.getValue(), recategorizationRequest); + Set typeIdsOfDictionariesWithDelete = manualRedactionDictionaryUpdateHandler.handleRemoveFromDictionaryAndReturnModifiedTypeIds(fileId, recategorizationRequest); @@ -254,6 +255,7 @@ public class ManualRedactionService { response.add(ManualAddResponse.builder().annotationId(recategorizationRequest.getAnnotationId()).commentId(commentId).build()); } + reprocess(dossierId, fileId); fileStatusPersistenceService.setLastManualChangeDate(fileId, OffsetDateTime.now()); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/PendingDictionaryEntryFactory.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/PendingDictionaryEntryFactory.java index bd376e63d..2991bce52 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/PendingDictionaryEntryFactory.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/PendingDictionaryEntryFactory.java @@ -9,6 +9,7 @@ import java.util.stream.Collectors; import org.springframework.stereotype.Service; +import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogMergeService; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Engine; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; @@ -172,7 +173,9 @@ public class PendingDictionaryEntryFactory { "legalBasis", manualChange.getLegalBasis(), "section", - manualChange.getSection())) + manualChange.getSection(), + "value", + manualChange.getValue())) .build()); return EntityLogEntry.builder() @@ -202,4 +205,45 @@ public class PendingDictionaryEntryFactory { .build(); } + + + public EntityLogEntry buildPendingImageRecategorizationEntry(ManualRecategorization manualChange, EntityLogEntry originalEntry) { + + var manualChanges = List.of(ManualChange.builder() + .manualRedactionType(ManualRedactionType.RECATEGORIZE) + .requestedDate(manualChange.getRequestDate()) + .processedDate(manualChange.getProcessedDate()) + .userId(manualChange.getUser()) + .propertyChanges(EntityLogMergeService.getPropertyChanges(manualChange)) + .build()); + + String reason = String.format("Image has been recategorized from %s to %s", originalEntry.getType(), manualChange.getType()); + + return EntityLogEntry.builder() + .id(originalEntry.getId()) + .value(originalEntry.getValue()) + .type(manualChange.getType()) + .entryType(originalEntry.getEntryType()) + .state(EntryState.PENDING) + .dictionaryEntry(manualChange.isAddToDictionary()) + .dossierDictionaryEntry(manualChange.isAddToAllDossiers()) + .reason(reason) + .legalBasis(reason) + .matchedRule("") + .containingNodeId(Collections.emptyList()) + .closestHeadline("") + .section("") + .positions(originalEntry.getPositions()) + .textAfter("") + .textBefore("") + .startOffset(-1) + .endOffset(-1) + .changes(Collections.emptyList()) + .manualChanges(manualChanges) + .engines(Set.of(Engine.MANUAL)) + .reference(Collections.emptySet()) + .importedRedactionIntersections(Collections.emptySet()) + .build(); + } + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml index d674bf548..5da7207a3 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml @@ -191,3 +191,5 @@ databaseChangeLog: file: db/changelog/tenant/sql/206-remove-manual-redactions-on-non-existing-pages.sql - include: file: db/changelog/tenant/122-add-legal-basis-variables-to-recategorize.yaml + - include: + file: db/changelog/tenant/123-add-value-to-recategorize.yaml diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/123-add-value-to-recategorize.yaml b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/123-add-value-to-recategorize.yaml new file mode 100644 index 000000000..8828243b9 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/123-add-value-to-recategorize.yaml @@ -0,0 +1,11 @@ +databaseChangeLog: + - changeSet: + id: add-legal-basis-variables-to-recategorize + author: ali + changes: + - addColumn: + tableName: manual_recategorization + columns: + - column: + name: value + type: VARCHAR(4000) \ No newline at end of file diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java index 42f473d6e..8a8cf2b87 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java @@ -6,17 +6,14 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; -import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionResultDetail; -import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionType; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DownloadRedactionFileStatusRepository; -import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService; - import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import com.fasterxml.jackson.databind.ObjectMapper; +import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionResultDetail; import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionResultMessage; +import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionType; import com.iqser.red.service.peristence.v1.server.integration.client.DownloadClient; import com.iqser.red.service.peristence.v1.server.integration.client.FileClient; import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; @@ -26,12 +23,13 @@ import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPers import com.iqser.red.service.persistence.management.v1.processor.model.DownloadJob; import com.iqser.red.service.persistence.management.v1.processor.service.download.DownloadMessageReceiver; import com.iqser.red.service.persistence.management.v1.processor.service.download.DownloadPreparationService; -import com.iqser.red.service.persistence.service.v1.api.shared.model.PrepareDownloadRequest; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DownloadRedactionFileStatusRepository; import com.iqser.red.service.persistence.service.v1.api.shared.model.PrepareDownloadWithOptionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.RemoveDownloadRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DownloadFileType; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; import com.iqser.red.service.redaction.report.v1.api.model.ReportResultMessage; +import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService; import com.knecon.fforesight.tenantcommons.TenantContext; import feign.FeignException; diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogMergeTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogMergeTest.java index c89565ec5..bad993284 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogMergeTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogMergeTest.java @@ -120,7 +120,7 @@ public class EntityLogMergeTest { ManualRedactions manualRedactions = provideManualRedactions(entryToAddId, entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId, fileId, rectangleToAddId); - var entityLog = provideEntityLog(entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId); + var entityLog = provideEntityLog(entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId, false); when(manualRedactionProviderService.getManualRedactions(any(), any())).thenReturn(manualRedactions); when(fileStatusService.getStatus(fileId)).thenReturn(FileModel.builder().excluded(false).dossierStatusId(dossierTemplateId).id(fileId).build()); @@ -237,7 +237,7 @@ public class EntityLogMergeTest { @Test - public void testUnprocessedDictChangesAreDirectlyAfterOriginEntry() { + public void testMergeEntityLogWithManualChangesOnDictRedaction() { String fileId = "fileId"; String dossierId = "dossierId"; @@ -250,6 +250,58 @@ public class EntityLogMergeTest { String entryLegalBasisId = UUID.randomUUID().toString(); String forceRedactionId = UUID.randomUUID().toString(); + ManualRedactions manualRedactions = provideManualRedactions(entryToAddId, entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId, fileId, rectangleToAddId); + + var entityLog = provideEntityLog(entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId, true); + + when(manualRedactionProviderService.getManualRedactions(any(), any())).thenReturn(manualRedactions); + when(fileStatusService.getStatus(fileId)).thenReturn(FileModel.builder().excluded(false).dossierStatusId(dossierTemplateId).id(fileId).build()); + when(fileManagementStorageService.getEntityLog(dossierId, fileId)).thenReturn(entityLog); + when(dossierService.getDossierById(dossierId)).thenReturn(DossierEntity.builder().dossierTemplateId(dossierTemplateId).build()); + when(dictionaryPersistenceService.getType(anyString())).thenReturn(TypeEntity.builder().isHint(false).build()); + when(fileStatusPersistenceService.getStatus(fileId)).thenReturn(FileEntity.builder().id(fileId).fileAttributes(Collections.emptyList()).build()); + when(fileStatusService.convertAttributes(any(), anyString())).thenReturn(Collections.emptyList()); + + EntityLog response = entityLogMergeService.mergeEntityLog(manualRedactions, entityLog, DossierEntity.builder().dossierTemplateId(dossierTemplateId).build()); + + assertNotNull(response); + assertFalse(response.getEntityLogEntry().isEmpty()); + + var optionalResizeEntryLogEntry = response.getEntityLogEntry() + .stream() + .filter(entityLogEntry1 -> entityLogEntry1.getId().equals(entryToResizeId)) + .findFirst(); + assertTrue(optionalResizeEntryLogEntry.isPresent()); + assertEquals(optionalResizeEntryLogEntry.get().getEntryType(), EntryType.ENTITY); + + var optionalLegalBasisEntryLogEntry = response.getEntityLogEntry() + .stream() + .filter(entityLogEntry1 -> entityLogEntry1.getId().equals(entryLegalBasisId)) + .findFirst(); + assertTrue(optionalLegalBasisEntryLogEntry.isPresent()); + assertEquals(optionalLegalBasisEntryLogEntry.get().getState(), EntryState.REMOVED); + + var optionalForceRedactionEntryLogEntry = response.getEntityLogEntry() + .stream() + .filter(entityLogEntry1 -> entityLogEntry1.getId().equals(forceRedactionId)) + .findFirst(); + assertTrue(optionalForceRedactionEntryLogEntry.isPresent()); + assertEquals(optionalForceRedactionEntryLogEntry.get().getState(), EntryState.REMOVED); + } + + + @Test + public void testUnprocessedDictChangesAreDirectlyAfterOriginEntry() { + + String fileId = "fileId"; + String dossierId = "dossierId"; + String dossierTemplateId = "dossierTemplateId"; + + String entryToRemoveId = UUID.randomUUID().toString(); + String entryToResizeId = UUID.randomUUID().toString(); + String entryLegalBasisId = UUID.randomUUID().toString(); + String forceRedactionId = UUID.randomUUID().toString(); + ManualRedactions manualRedactions = new ManualRedactions(); List positions = new ArrayList<>(); @@ -265,7 +317,7 @@ public class EntityLogMergeTest { .fileId("file") .build())); - var entityLog = provideEntityLog(entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId); + var entityLog = provideEntityLog(entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId, false); when(manualRedactionProviderService.getManualRedactions(any(), any())).thenReturn(manualRedactions); when(fileStatusService.getStatus(fileId)).thenReturn(FileModel.builder().excluded(false).dossierStatusId(dossierTemplateId).id(fileId).build()); @@ -284,7 +336,7 @@ public class EntityLogMergeTest { } - private EntityLog provideEntityLog(String entryToRemoveId, String entryToResizeId, String entryLegalBasisId, String forceRedactionId) { + private EntityLog provideEntityLog(String entryToRemoveId, String entryToResizeId, String entryLegalBasisId, String forceRedactionId, boolean dictEntry) { List positions = new ArrayList<>(); positions.add(new Position(1, 1, 1, 1, 1)); @@ -296,7 +348,7 @@ public class EntityLogMergeTest { .value("Luke Skywalker") .entryType(EntryType.ENTITY) .state(EntryState.APPLIED) - .dictionaryEntry(true) + .dictionaryEntry(dictEntry) .build(), EntityLogEntry.builder() .id(entryToResizeId) @@ -304,7 +356,7 @@ public class EntityLogMergeTest { .value("Darth Vader") .entryType(EntryType.ENTITY) .state(EntryState.APPLIED) - .dictionaryEntry(true) + .dictionaryEntry(dictEntry) .positions(positions) .build(), EntityLogEntry.builder() @@ -313,7 +365,7 @@ public class EntityLogMergeTest { .value("Darth Luke") .entryType(EntryType.ENTITY) .state(EntryState.APPLIED) - .dictionaryEntry(true) + .dictionaryEntry(dictEntry) .positions(positions) .build(), EntityLogEntry.builder() @@ -322,7 +374,7 @@ public class EntityLogMergeTest { .value("Darth Luke") .entryType(EntryType.ENTITY) .state(EntryState.APPLIED) - .dictionaryEntry(true) + .dictionaryEntry(dictEntry) .positions(positions) .build()), Collections.emptyList(), @@ -381,6 +433,7 @@ public class EntityLogMergeTest { .positions(positions) .requestDate(OffsetDateTime.now()) .updateDictionary(false) + .addToAllDossiers(false) .user("User") .fileId("file") .build())) diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java index ac628e195..1eb8c96cf 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java @@ -376,6 +376,20 @@ public class FileTest extends AbstractPersistenceServerServiceTest { .value("value entry") .state(EntryState.APPLIED) .entryType(EntryType.ENTITY) + .build(), + EntityLogEntry.builder() + .id("forceRedactionAnnotation") + .type(type.getType()) + .value("value entry 2") + .state(EntryState.APPLIED) + .entryType(EntryType.ENTITY) + .build(), + EntityLogEntry.builder() + .id("legalBasisChangeAnnotation") + .type(type.getType()) + .value("value entry 3") + .state(EntryState.APPLIED) + .entryType(EntryType.ENTITY) .build()), null, 0, diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java index d712d5479..831c87a36 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java @@ -4,6 +4,7 @@ import static com.iqser.red.service.persistence.management.v1.processor.utils.Ty import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; @@ -44,7 +45,9 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequestModel; @@ -803,7 +806,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { @Test - public void MtestEnlargeResizeRedactionInDossierTemplateDictionaryWithAddToAllDossiers() { + public void testEnlargeResizeRedactionInDossierTemplateDictionaryWithAddToAllDossiers() { // preparíng prerequisites var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); @@ -1194,6 +1197,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .addToAllDossiers(true) .legalBasis("") .section("section") + .value(lukeSkywalker) .build()), false); @@ -1279,6 +1283,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .addToAllDossiers(false) .legalBasis("") .section("section") + .value(lukeSkywalker) .build()), false); @@ -1539,6 +1544,38 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); var file = fileTesterAndProvider.testAndProvideFile(dossier); + var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", false); + + var entityLog = new EntityLog(1, + 1, + List.of(EntityLogEntry.builder() + .id("forceRedactionAnnotation") + .type(type.getType()) + .value("lukeSkywalker") + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .legalBasis("legal basis") + .positions(List.of(new Position(1, 1, 1, 1, 1))) + .build(), + EntityLogEntry.builder() + .id("forceRedactionAnnotation2") + .type(type.getType()) + .value("lukeSkywalker") + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .legalBasis("legal basis") + .positions(List.of(new Position(1, 1, 1, 1, 1))) + .build()), + null, + 0, + 0, + 0, + 0); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any(), any(), anyBoolean())).thenReturn(entityLog); + manualRedactionClient.forceRedactionBulk(dossier.getId(), file.getId(), Set.of(ForceRedactionRequestModel.builder().annotationId("forceRedactionAnnotation").comment("comment").legalBasis("1").build())); @@ -1759,7 +1796,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.saveEntityLog(dossier.getId(), file.getId(), entityLog); - when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyBoolean())).thenReturn(entityLog); manualRedactionClient.legalBasisChangeBulk(dossier.getId(), file.getId(), @@ -1869,7 +1906,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.saveEntityLog(dossier.getId(), file.getId(), entityLog); - when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyBoolean())).thenReturn(entityLog); manualRedactionClient.legalBasisChangeBulk(dossier.getId(), file.getId(), @@ -1894,13 +1931,13 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .anyMatch(entry -> entry.getLegalBasis().equals("legalBasis"))); var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, false); - assertEquals(unprocessedManualRedactions.buildAll().size(), 1); + assertEquals(unprocessedManualRedactions.buildAll().size(), 2); assertTrue(unprocessedManualRedactions.getLegalBasisChanges() .stream() .anyMatch(entry -> entry.getLegalBasis().equals("legalBasis"))); var unprocessedManualRedactionsWithDict = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true); - assertEquals(unprocessedManualRedactionsWithDict.buildAll().size(), 2); + assertEquals(unprocessedManualRedactionsWithDict.buildAll().size(), 3); assertTrue(unprocessedManualRedactionsWithDict.getLegalBasisChanges() .stream() .anyMatch(entry -> entry.getLegalBasis().equals("legalBasis"))); @@ -1961,6 +1998,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .addToAllDossiers(true) .legalBasis("") .section("section") + .value("other value") .build(); var recatModelLongLegalBasis = RecategorizationRequestModel.builder() .type(type.getType()) @@ -1974,6 +2012,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .annotationId("annotationId3") .addToDictionary(true) .section("section") + .value("some value") .addToAllDossiers(true) .build(); @@ -2067,4 +2106,205 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .anyMatch(entry -> entry.getSection().equals("section"))); } + + @Test + public void testManualRecategorizationOnDictionaryRedaction() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + + var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", false, 100); + var type2 = typeProvider.testAndProvideType(dossierTemplate, null, "type2", false, 110); + + var entityLogEntry = EntityLogEntry.builder() + .id("annotationId") + .type(type.getType()) + .value("lukeSkywalker") + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .legalBasis("legal basis") + .positions(List.of(new Position(1, 1, 1, 1, 1))) + .build(); + var entityLog = new EntityLog(1, + 1, + List.of(entityLogEntry), + null, + 0, + 0, + 0, + 0); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any(), any(), anyBoolean())).thenReturn(entityLog); + + var recategorizationRequestModel = RecategorizationRequestModel.builder() + .type(type2.getType()) + .annotationId("annotationId") + .addToDictionary(false) + .addToAllDossiers(false) + .legalBasis("") + .build(); + + manualRedactionClient.recategorizeBulk(dossier.getId(), file.getId(), Set.of(recategorizationRequestModel), false); + + var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true); + + assertEquals(allManualRedactions.getRecategorizations().size(), 1); + assertEquals(allManualRedactions.getEntriesToAdd().size(), 1); + var entryToAdd = allManualRedactions.getEntriesToAdd().stream().findFirst().get(); + assertFalse(entryToAdd.isAddToDictionary()); + assertFalse(entryToAdd.isAddToDossierDictionary()); + assertEquals(entryToAdd.getValue(), entityLogEntry.getValue()); + assertEquals(entryToAdd.getType(), entityLogEntry.getType()); + } + + + @Test + public void testManualLegalBasisChangeOnDictionaryRedaction() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + + var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", false); + + var entityLogEntry = EntityLogEntry.builder() + .id("annotationId") + .type(type.getType()) + .value("lukeSkywalker") + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .legalBasis("legal basis") + .positions(List.of(new Position(1, 1, 1, 1, 1))) + .build(); + var entityLog = new EntityLog(1, + 1, + List.of(entityLogEntry), + null, + 0, + 0, + 0, + 0); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any(), any(), anyBoolean())).thenReturn(entityLog); + + var legalBasisChangeRequestModel = LegalBasisChangeRequestModel.builder() + .annotationId("annotationId") + .legalBasis("new legal basis") + .value(entityLogEntry.getValue()) + .build(); + + manualRedactionClient.legalBasisChangeBulk(dossier.getId(), file.getId(), Set.of(legalBasisChangeRequestModel)); + + var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true); + + assertEquals(allManualRedactions.getLegalBasisChanges().size(), 1); + assertEquals(allManualRedactions.getEntriesToAdd().size(), 1); + var entryToAdd = allManualRedactions.getEntriesToAdd().stream().findFirst().get(); + assertFalse(entryToAdd.isAddToDictionary()); + assertFalse(entryToAdd.isAddToDossierDictionary()); + assertEquals(entryToAdd.getValue(), entityLogEntry.getValue()); + assertEquals(entryToAdd.getLegalBasis(), entityLogEntry.getLegalBasis()); + } + + + @Test + public void testManualResizeOnDictionaryRedaction() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + + var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", false); + + var entityLogEntry = EntityLogEntry.builder() + .id("annotationId") + .type(type.getType()) + .value("lukeSkywalker") + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .legalBasis("legal basis") + .positions(List.of(new Position(1, 1, 1, 1, 1))) + .build(); + var entityLog = new EntityLog(1, + 1, + List.of(entityLogEntry), + null, + 0, + 0, + 0, + 0); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any(), any(), anyBoolean())).thenReturn(entityLog); + + var resizeRedactionRequestModel = ResizeRedactionRequestModel.builder() + .annotationId("annotationId") + .value("lukeSkywalker resized") + .updateDictionary(false) + .addToAllDossiers(false) + .positions(List.of(Rectangle.builder().page(1).height(1).width(2).topLeftX(1).topLeftY(1).build())) + .build(); + + manualRedactionClient.resizeRedactionBulk(dossier.getId(), file.getId(), Set.of(resizeRedactionRequestModel), false); + + var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true); + + assertEquals(allManualRedactions.getResizeRedactions().size(), 1); + assertEquals(allManualRedactions.getEntriesToAdd().size(), 1); + var entryToAdd = allManualRedactions.getEntriesToAdd().stream().findFirst().get(); + assertFalse(entryToAdd.isAddToDictionary()); + assertFalse(entryToAdd.isAddToDossierDictionary()); + assertEquals(entryToAdd.getValue(), entityLogEntry.getValue()); + } + + + @Test + public void testManualForceRedactionOnDictionaryRedaction() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + + var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", false); + + var entityLogEntry = EntityLogEntry.builder() + .id("annotationId") + .type(type.getType()) + .value("lukeSkywalker") + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .legalBasis("legal basis") + .positions(List.of(new Position(1, 1, 1, 1, 1))) + .build(); + var entityLog = new EntityLog(1, + 1, + List.of(entityLogEntry), + null, + 0, + 0, + 0, + 0); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any(), any(), anyBoolean())).thenReturn(entityLog); + + var forceRedactionRequestModel = ForceRedactionRequestModel.builder() + .annotationId("annotationId") + .build(); + + manualRedactionClient.forceRedactionBulk(dossier.getId(), file.getId(), Set.of(forceRedactionRequestModel)); + + var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true); + + assertEquals(allManualRedactions.getForceRedactions().size(), 1); + assertEquals(allManualRedactions.getEntriesToAdd().size(), 1); + var entryToAdd = allManualRedactions.getEntriesToAdd().stream().findFirst().get(); + assertFalse(entryToAdd.isAddToDictionary()); + assertFalse(entryToAdd.isAddToDossierDictionary()); + assertEquals(entryToAdd.getValue(), entityLogEntry.getValue()); + } + } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRecategorization.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRecategorization.java index a6155f94e..91bcbd8e3 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRecategorization.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRecategorization.java @@ -18,6 +18,7 @@ public class ManualRecategorization extends BaseAnnotation { private boolean addToDictionary; private boolean addToAllDossiers; private String section; + private String value; @Override diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/RecategorizationRequestModel.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/RecategorizationRequestModel.java index 367264dd4..ef3270c35 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/RecategorizationRequestModel.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/RecategorizationRequestModel.java @@ -21,5 +21,6 @@ public class RecategorizationRequestModel { boolean addToAllDossiers; String legalBasis; String section; + String value; }