From 0b173ec9305159c2d3dee0e801010e4c4ab5d8be Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Fri, 25 Aug 2023 16:21:01 +0200 Subject: [PATCH 1/7] RED-7317: Keep user-edited paragraph/location when recategorizing entity * refactor of ManualRedactionService, still WIP --- .../controller/ManualRedactionController.java | 138 +++--- .../resource/ManualRedactionResource.java | 32 +- .../RemoveFalsePositiveManualRedactions6.java | 2 +- .../FileStatusProcessingUpdateService.java | 1 + ...anualRedactionDictionaryUpdateHandler.java | 92 ++++ .../ManualRedactionService.java | 425 ++++++++---------- ...ageRecategorizationPersistenceService.java | 8 +- .../RedactionLogMergeService.java | 5 +- .../v1/server/integration/tests/FileTest.java | 25 +- .../tests/ManualRedactionTest.java | 44 +- .../annotations/AddRedactionRequest.java | 2 +- .../model/annotations/BaseManualRequest.java | 13 + .../annotations/ForceRedactionRequest.java | 2 +- .../ImageRecategorizationRequest.java | 21 - .../ManualRequestWithDictionary.java | 14 + .../annotations/RecategorizationRequest.java | 44 ++ .../annotations/RemoveRedactionRequest.java | 2 +- .../annotations/ResizeRedactionRequest.java | 2 +- ...quest.java => AddCommentRequestModel.java} | 2 +- ...est.java => AddRedactionRequestModel.java} | 4 +- ...eRequest.java => ApproveRequestModel.java} | 2 +- ...t.java => ForceRedactionRequestModel.java} | 2 +- .../manual/ImageRecategorizationRequest.java | 18 - ...java => LegalBasisChangeRequestModel.java} | 2 +- ....java => ManualRedactionWrapperModel.java} | 4 +- .../manual/RecategorizationRequestModel.java | 23 + ....java => RemoveRedactionRequestModel.java} | 2 +- ....java => ResizeRedactionRequestModel.java} | 2 +- 28 files changed, 522 insertions(+), 411 deletions(-) create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionDictionaryUpdateHandler.java rename persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/{ => manualredactions}/ManualRedactionService.java (64%) create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/BaseManualRequest.java delete mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ImageRecategorizationRequest.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithDictionary.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RecategorizationRequest.java rename persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/{AddCommentRequest.java => AddCommentRequestModel.java} (89%) rename persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/{AddRedactionRequest.java => AddRedactionRequestModel.java} (92%) rename persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/{ApproveRequest.java => ApproveRequestModel.java} (88%) rename persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/{ForceRedactionRequest.java => ForceRedactionRequestModel.java} (90%) delete mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ImageRecategorizationRequest.java rename persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/{LegalBasisChangeRequest.java => LegalBasisChangeRequestModel.java} (90%) rename persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/{ManualRedactionWrapper.java => ManualRedactionWrapperModel.java} (70%) create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/RecategorizationRequestModel.java rename persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/{RemoveRedactionRequest.java => RemoveRedactionRequestModel.java} (90%) rename persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/{ResizeRedactionRequest.java => ResizeRedactionRequestModel.java} (94%) 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 549d217fe..b8a575214 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 @@ -23,11 +23,12 @@ import org.springframework.web.bind.annotation.RestController; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService; import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService; -import com.iqser.red.service.persistence.management.v1.processor.service.ManualRedactionService; +import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; import com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource; import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse; +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.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse; @@ -39,14 +40,14 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations 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.annotations.entitymapped.ManualResizeRedaction; import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ImageRecategorizationRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ManualRedactionWrapper; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequest; +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; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ManualRedactionWrapperModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel; import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; import lombok.RequiredArgsConstructor; @@ -66,43 +67,42 @@ public class ManualRedactionController implements ManualRedactionResource { private final AccessControlService accessControlService; + private ManualRedactionWrapperModel getLatestManualRedactionForAnnotationId(ManualRedactions manualRedactions, String annotationId) { - private ManualRedactionWrapper getLatestManualRedactionForAnnotationId(ManualRedactions manualRedactions, String annotationId) { - - final List manualRedactionWrappers = new ArrayList<>(); + final List manualRedactionWrappers = new ArrayList<>(); manualRedactions.getEntriesToAdd() .stream() .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item))); + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); manualRedactions.getImageRecategorization() .stream() .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item))); + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); manualRedactions.getIdsToRemove() .stream() .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item))); + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); manualRedactions.getForceRedactions() .stream() .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item))); + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); manualRedactions.getLegalBasisChanges() .stream() .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item))); + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); manualRedactions.getResizeRedactions() .stream() .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item))); + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); var sortedManualRedactionWrappers = manualRedactionWrappers.stream() - .sorted(Comparator.comparing(ManualRedactionWrapper::getDate, Comparator.nullsLast(Comparator.reverseOrder()))) + .sorted(Comparator.comparing(ManualRedactionWrapperModel::getDate, Comparator.nullsLast(Comparator.reverseOrder()))) .collect(Collectors.toList()); return sortedManualRedactionWrappers.isEmpty() ? null : sortedManualRedactionWrappers.get(0); @@ -118,7 +118,7 @@ public class ManualRedactionController implements ManualRedactionResource { ManualRedactions manualRedactions = manualRedactionService.getManualRedactions(fileId); - Map manualRedactionWrappers = getLatestManualRedactionsForAnnotationIds(manualRedactions, annotationIds); + Map manualRedactionWrappers = getLatestManualRedactionsForAnnotationIds(manualRedactions, annotationIds); if (manualRedactionWrappers.isEmpty()) { throw new NotFoundException(String.format("ManualRedaction with annotationIds %s could not be found.", annotationIds)); @@ -127,7 +127,7 @@ public class ManualRedactionController implements ManualRedactionResource { List manualRedactionEntries = manualRedactionWrappers.values() .stream() .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualRedactionEntry) - .map(ManualRedactionWrapper::getId) + .map(ManualRedactionWrapperModel::getId) .collect(Collectors.toList()); if (!manualRedactionEntries.isEmpty()) { manualRedactionService.deleteAddRedaction(dossierId, fileId, manualRedactionEntries); @@ -143,7 +143,7 @@ public class ManualRedactionController implements ManualRedactionResource { List idRemovals = manualRedactionWrappers.values() .stream() .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof IdRemoval) - .map(ManualRedactionWrapper::getId) + .map(ManualRedactionWrapperModel::getId) .collect(Collectors.toList()); if (!idRemovals.isEmpty()) { @@ -160,7 +160,7 @@ public class ManualRedactionController implements ManualRedactionResource { List manualForceRedactions = manualRedactionWrappers.values() .stream() .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualForceRedaction) - .map(ManualRedactionWrapper::getId) + .map(ManualRedactionWrapperModel::getId) .collect(Collectors.toList()); if (!manualForceRedactions.isEmpty()) { @@ -177,7 +177,7 @@ public class ManualRedactionController implements ManualRedactionResource { List manualImageRecategorizations = manualRedactionWrappers.values() .stream() .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualImageRecategorization) - .map(ManualRedactionWrapper::getId) + .map(ManualRedactionWrapperModel::getId) .collect(Collectors.toList()); if (!manualImageRecategorizations.isEmpty()) { @@ -194,7 +194,7 @@ public class ManualRedactionController implements ManualRedactionResource { List manualLegalBasisChanges = manualRedactionWrappers.values() .stream() .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualLegalBasisChange) - .map(ManualRedactionWrapper::getId) + .map(ManualRedactionWrapperModel::getId) .collect(Collectors.toList()); if (!manualLegalBasisChanges.isEmpty()) { @@ -211,7 +211,7 @@ public class ManualRedactionController implements ManualRedactionResource { List manualResizeRedactions = manualRedactionWrappers.values() .stream() .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualResizeRedaction) - .map(ManualRedactionWrapper::getId) + .map(ManualRedactionWrapperModel::getId) .collect(Collectors.toList()); if (!manualResizeRedactions.isEmpty()) { @@ -227,9 +227,9 @@ public class ManualRedactionController implements ManualRedactionResource { } - private Map getLatestManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set annotationIds) { + private Map getLatestManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set annotationIds) { - Map result = new HashMap<>(); + Map result = new HashMap<>(); annotationIds.forEach(annotationId -> { var last = getLatestManualRedactionForAnnotationId(manualRedactions, annotationId); if (last != null) { @@ -276,7 +276,7 @@ public class ManualRedactionController implements ManualRedactionResource { public CommentResponse addComment(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @PathVariable(ANNOTATION_ID) String annotationId, - @RequestBody AddCommentRequest addCommentRequest) { + @RequestBody AddCommentRequestModel addCommentRequest) { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId); @@ -301,41 +301,38 @@ public class ManualRedactionController implements ManualRedactionResource { @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')") public List addRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestBody Set addRedactionRequests) { + @RequestBody Set addRedactionRequests) { var dossier = dossierManagementService.getDossierById(dossierId, false, false); accessControlService.verifyFileIsNotApproved(dossierId, fileId); - if(addRedactionRequests.stream().anyMatch(AddRedactionRequest::isAddToAllDossiers)){ + if (addRedactionRequests.stream().anyMatch(AddRedactionRequestModel::isAddToAllDossiers)) { accessControlService.verifyUserIsApprover(dossierId); } else { accessControlService.verifyUserIsMemberOrApprover(dossierId); } - List requests = new ArrayList<>(); + List requests = addRedactionRequests.stream() + .map(addRedactionRequest -> AddRedactionRequest.builder() + .value(addRedactionRequest.getValue()) + .legalBasis(addRedactionRequest.getLegalBasis()) + .user(KeycloakSecurity.getUserId()) + .dossierTemplateTypeId(toTypeId(addRedactionRequest.getType(), dossier.getDossierTemplateId())) + .reason(addRedactionRequest.getReason()) + .addToDictionary(addRedactionRequest.isAddToDictionary()) + .status(AnnotationStatus.APPROVED) + .comment(addRedactionRequest.getComment() != null ? addRedactionRequest.getComment().getText() : null) + .section(addRedactionRequest.getSection()) + .rectangle(addRedactionRequest.isRectangle()) + .addToAllDossiers(addRedactionRequest.isAddToAllDossiers()) + .forceAddToDictionary(addRedactionRequest.isForceAddToDictionary()) + .positions(addRedactionRequest.getPositions()) + .sourceId(addRedactionRequest.getSourceId()) + .dossierId(dossierId) + .dictionaryEntryType(addRedactionRequest.getDictionaryEntryType()) + .build()) + .collect(Collectors.toList()); - for (var addRedactionRequest : addRedactionRequests) { - - var addRedactionRequestBuilder = com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest.builder() - .value(addRedactionRequest.getValue()) - .legalBasis(addRedactionRequest.getLegalBasis()) - .user(KeycloakSecurity.getUserId()) - .dossierTemplateTypeId(toTypeId(addRedactionRequest.getType(), dossier.getDossierTemplateId())) - .reason(addRedactionRequest.getReason()) - .addToDictionary(addRedactionRequest.isAddToDictionary()) - .status(AnnotationStatus.APPROVED) - .comment(addRedactionRequest.getComment() != null ? addRedactionRequest.getComment().getText() : null) - .section(addRedactionRequest.getSection()) - .rectangle(addRedactionRequest.isRectangle()) - .addToAllDossiers(addRedactionRequest.isAddToAllDossiers()) - .forceAddToDictionary(addRedactionRequest.isForceAddToDictionary()) - .positions(addRedactionRequest.getPositions()) - .sourceId(addRedactionRequest.getSourceId()) - .dossierId(dossierId) - .dictionaryEntryType(addRedactionRequest.getDictionaryEntryType()); - - requests.add(addRedactionRequestBuilder.build()); - } List responseList = manualRedactionService.addAddRedaction(dossierId, fileId, requests); responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder() .userId(KeycloakSecurity.getUserId()) @@ -351,10 +348,10 @@ public class ManualRedactionController implements ManualRedactionResource { @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')") public List removeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestBody Set removeRedactionRequests) { + @RequestBody Set removeRedactionRequests) { accessControlService.verifyFileIsNotApproved(dossierId, fileId); - if(removeRedactionRequests.stream().anyMatch(RemoveRedactionRequest::isRemoveFromAllDossiers)){ + if (removeRedactionRequests.stream().anyMatch(RemoveRedactionRequestModel::isRemoveFromAllDossiers)) { accessControlService.verifyUserIsApprover(dossierId); } else { accessControlService.verifyUserIsMemberOrApprover(dossierId); @@ -393,7 +390,7 @@ public class ManualRedactionController implements ManualRedactionResource { @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')") public List forceRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestBody Set forceRedactionRequests) { + @RequestBody Set forceRedactionRequests) { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsMemberOrApprover(dossierId); @@ -424,7 +421,7 @@ public class ManualRedactionController implements ManualRedactionResource { @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')") public List legalBasisChangeBulk(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestBody Set legalBasisChangeRequests) { + @RequestBody Set legalBasisChangeRequests) { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsMemberOrApprover(dossierId); @@ -456,31 +453,33 @@ public class ManualRedactionController implements ManualRedactionResource { @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')") - public List recategorizeImageBulk(@PathVariable(DOSSIER_ID) String dossierId, - @PathVariable(FILE_ID) String fileId, - @RequestBody Set imageRecategorizationRequests) { + public List recategorizeBulk(@PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, + @RequestBody Set recategorizationRequests) { var dossier = dossierManagementService.getDossierById(dossierId, false, false); accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsMemberOrApprover(dossierId); - List requests = imageRecategorizationRequests.stream() - .map(imageRecategorizationRequest -> com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ImageRecategorizationRequest.builder() - .annotationId(imageRecategorizationRequest.getAnnotationId()) + List requests = recategorizationRequests.stream() + .map(recategorizationRequest -> com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RecategorizationRequest.builder() + .annotationId(recategorizationRequest.getAnnotationId()) .user(KeycloakSecurity.getUserId()) .status(AnnotationStatus.APPROVED) - .typeId(toTypeId(imageRecategorizationRequest.getType(), dossier.getDossierTemplateId())) - .comment(imageRecategorizationRequest.getComment()) + .typeId(toTypeId(recategorizationRequest.getType(), dossier.getDossierTemplateId())) + .comment(recategorizationRequest.getComment()) + .addToDictionary(recategorizationRequest.isAddToDictionary()) + .addToAllDossiers(recategorizationRequest.isAddToAllDossiers()) .build()) .collect(Collectors.toList()); - List responseList = manualRedactionService.addImageRecategorization(dossierId, fileId, requests); + List responseList = manualRedactionService.addRecategorization(dossierId, fileId, requests); responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder() .userId(KeycloakSecurity.getUserId()) .objectId(fileId) .category(AuditCategory.DOCUMENT.name()) - .message("Image was recategorized") + .message("Entity was recategorized.") .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId())) .build())); @@ -491,7 +490,8 @@ public class ManualRedactionController implements ManualRedactionResource { @PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')") public List resizeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestBody Set resizeRedactionRequests) { + @RequestBody Set resizeRedactionRequests) { + accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsMemberOrApprover(dossierId); diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java index 5e8c09361..5cd1ff519 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java @@ -15,13 +15,13 @@ import org.springframework.web.bind.annotation.ResponseStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ImageRecategorizationRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequest; +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; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -58,7 +58,7 @@ public interface ManualRedactionResource { CommentResponse addComment(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @PathVariable(ANNOTATION_ID) String annotationId, - @RequestBody AddCommentRequest addCommentRequest); + @RequestBody AddCommentRequestModel addCommentRequest); @ResponseStatus(value = HttpStatus.NO_CONTENT) @@ -77,7 +77,7 @@ public interface ManualRedactionResource { @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) List addRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestBody Set addRedactionRequest); + @RequestBody Set addRedactionRequest); @ResponseStatus(value = HttpStatus.OK) @@ -86,7 +86,7 @@ public interface ManualRedactionResource { @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) List removeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestBody Set removeRedactionRequests); + @RequestBody Set removeRedactionRequests); @ResponseStatus(value = HttpStatus.OK) @@ -95,7 +95,7 @@ public interface ManualRedactionResource { @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) List forceRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestBody Set forceRedactionRequests); + @RequestBody Set forceRedactionRequests); @ResponseStatus(value = HttpStatus.OK) @@ -104,16 +104,16 @@ public interface ManualRedactionResource { @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) List legalBasisChangeBulk(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestBody Set legalBasisChangeRequests); + @RequestBody Set legalBasisChangeRequests); @ResponseStatus(value = HttpStatus.OK) @PostMapping(value = MANUAL_REDACTION_REST_PATH + "/bulk/redaction/recategorize" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Recategorizes the images list", description = "None") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) - List recategorizeImageBulk(@PathVariable(DOSSIER_ID) String dossierId, - @PathVariable(FILE_ID) String fileId, - @RequestBody Set imageRecategorizationRequests); + List recategorizeBulk(@PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, + @RequestBody Set recategorizationRequests); @ResponseStatus(value = HttpStatus.OK) @@ -122,7 +122,7 @@ public interface ManualRedactionResource { @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) List resizeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestBody Set resizeRedactionRequests); + @RequestBody Set resizeRedactionRequests); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/RemoveFalsePositiveManualRedactions6.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/RemoveFalsePositiveManualRedactions6.java index 5bdd9d890..4cfe4e15e 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/RemoveFalsePositiveManualRedactions6.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/RemoveFalsePositiveManualRedactions6.java @@ -6,7 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.service.ManualRedactionService; +import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusProcessingUpdateService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusProcessingUpdateService.java index 1f8d07ea5..0693c05ad 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusProcessingUpdateService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusProcessingUpdateService.java @@ -7,6 +7,7 @@ import org.springframework.retry.support.RetryTemplate; import org.springframework.web.bind.annotation.RestController; import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException; +import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.settings.FileManagementServiceSettings; 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 new file mode 100644 index 000000000..71109936c --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionDictionaryUpdateHandler.java @@ -0,0 +1,92 @@ +package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.springframework.stereotype.Service; + +import com.iqser.red.service.dictionarymerge.commons.DictionaryEntry; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; +import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; +import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithDictionary; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; + +import feign.FeignException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +@RequiredArgsConstructor +public class ManualRedactionDictionaryUpdateHandler { + + private final DictionaryManagementService dictionaryManagementService; + + + public Set handleAddToDictionary(String fileId, String dossierId, ManualRequestWithDictionary manualRequestWithDictionary) { + + if (!manualRequestWithDictionary.isApproved()) { + return Collections.emptySet(); + } + Set typeIdsOfModifiedDictionaries = new HashSet<>(); + + String dossierTemplateTypeId = manualRequestWithDictionary.getDossierTemplateTypeId(); + String value = manualRequestWithDictionary.getValue(); + DictionaryEntryType dictionaryEntryType = manualRequestWithDictionary.getDictionaryEntryType(); + + if (manualRequestWithDictionary.isAddToAllDossiers()) { + List dictionaryEntriesToUnDelete = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplateTypeId, value); + dictionaryEntriesToUnDelete.forEach(entry -> { + typeIdsOfModifiedDictionaries.add(entry.getTypeId()); + addToDictionary(entry.getTypeId(), manualRequestWithDictionary.getValue(), dossierId, fileId, manualRequestWithDictionary.getDictionaryEntryType()); + }); + addToDictionary(dossierTemplateTypeId, value, dossierId, fileId, dictionaryEntryType); + typeIdsOfModifiedDictionaries.add(dossierTemplateTypeId); + } else { + addToDictionary(dossierTemplateTypeId + ":" + dossierId, value, dossierId, fileId, dictionaryEntryType); + typeIdsOfModifiedDictionaries.add(dossierTemplateTypeId + ":" + dossierId); + } + + return typeIdsOfModifiedDictionaries; + } + + + public boolean revertAddToDictionary(String fileId, String dossierId, ManualRedactionEntryEntity manualRedactionToRevert) { + + if (!manualRedactionToRevert.getStatus().equals(AnnotationStatus.APPROVED) || manualRedactionToRevert.isAddToDictionary()) { + return false; + } + + manualRedactionToRevert.getTypeIdsOfModifiedDictionaries().forEach(typeId -> { + removeFromDictionary(typeId, manualRedactionToRevert.getValue(), dossierId, fileId, manualRedactionToRevert.getDictionaryEntryType()); + }); + return true; + } + + + private void addToDictionary(String typeId, String value, String dossierId, String fileId, DictionaryEntryType dictionaryEntryType) { + + try { + log.debug("Adding entry: {} to {} for {} / {}", value, typeId, dossierId, fileId); + dictionaryManagementService.addEntries(typeId, List.of(value), false, false, dictionaryEntryType != null ? dictionaryEntryType : DictionaryEntryType.ENTRY); + } catch (Exception e) { + throw new BadRequestException(e.getMessage()); + } + } + + + private void removeFromDictionary(String typeId, String value, String dossierId, String fileId, DictionaryEntryType dictionaryEntryType) { + + try { + log.debug("Deleting entries to {} for {} / {}", typeId, dossierId, fileId); + dictionaryManagementService.deleteEntries(typeId, List.of(value), dictionaryEntryType != null ? dictionaryEntryType : DictionaryEntryType.ENTRY); + } catch (FeignException e) { + throw new BadRequestException(e.getMessage()); + } + } + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/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 similarity index 64% rename from persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ManualRedactionService.java rename to persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java index 0fbde10e3..01b69b8be 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/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 @@ -1,35 +1,69 @@ -package com.iqser.red.service.persistence.management.v1.processor.service; +package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions; + +import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId; + +import java.nio.charset.StandardCharsets; +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import com.google.common.hash.HashFunction; import com.google.common.hash.Hashing; -import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.*; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.CommentEntity; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualImageRecategorizationEntity; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualResizeRedactionEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; 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.NotFoundException; +import com.iqser.red.service.persistence.management.v1.processor.service.AnalysisFlagsCalculationService; +import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService; +import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; +import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; +import com.iqser.red.service.persistence.management.v1.processor.service.ManualRedactionProviderService; +import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService; +import com.iqser.red.service.persistence.management.v1.processor.service.StopwordService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.*; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.*; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.CommentPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ForceRedactionPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ImageRecategorizationPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.LegalBasisChangePersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService; +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.AnnotationStatus; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.BaseManualRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest; +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.ManualAddResponse; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithDictionary; +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.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.IdRemoval; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; 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.redactionlog.RedactionLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; + import feign.FeignException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.nio.charset.StandardCharsets; -import java.time.OffsetDateTime; -import java.time.temporal.ChronoUnit; -import java.util.*; - -import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId; @Slf4j @Service @@ -54,6 +88,7 @@ public class ManualRedactionService { private final RedactionLogService redactionLogService; private final DictionaryManagementService dictionaryManagementService; private final HashFunction hashFunction = Hashing.murmur3_128(); + private final ManualRedactionDictionaryUpdateHandler manualRedactionDictionaryUpdateHandler; @Transactional @@ -63,44 +98,29 @@ public class ManualRedactionService { dossierPersistenceService.getAndValidateDossier(dossierId); - // validate add to dossier template dictionaries - addRedactionRequests.forEach(request -> dictionaryManagementService.validateAddRemoveToDossierTemplateDictionary(request.getDossierTemplateTypeId(), - request.isAddToDictionary(), - request.isAddToAllDossiers())); + for (AddRedactionRequest addRedactionRequest : addRedactionRequests) { + validateDictionaries(addRedactionRequest); + validatePositions(fileId, addRedactionRequest); + + String annotationId = hashFunction.hashString(fileId + addRedactionRequest, StandardCharsets.UTF_8).toString(); - boolean actionPerformed = false; - for (var addRedactionRequest : addRedactionRequests) { if (addRedactionRequest.isAddToDictionary()) { - validateDictionary(addRedactionRequest); + Set typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.handleAddToDictionary(fileId, dossierId, addRedactionRequest); + addRedactionPersistenceService.updateStatus(fileId, annotationId, addRedactionRequest.getStatus(), true, typeIdsOfModifiedDictionaries); + } else { + addRedactionPersistenceService.updateStatus(fileId, annotationId, addRedactionRequest.getStatus(), false, null); } - validatePositions(fileId, addRedactionRequest); - String annotationId = hashFunction.hashString(fileId + addRedactionRequest, StandardCharsets.UTF_8).toString(); addRedactionPersistenceService.insert(fileId, annotationId, addRedactionRequest); - Long commentId = null; - if (addRedactionRequest.getComment() != null) { - commentId = addComment(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser()).getId(); - } - - handleAddToDictionary(fileId, - annotationId, - addRedactionRequest.getDossierTemplateTypeId(), - addRedactionRequest.getValue(), - addRedactionRequest.getStatus(), - addRedactionRequest.isAddToDictionary(), - addRedactionRequest.isAddToAllDossiers(), - false, - dossierId, - addRedactionRequest.getDictionaryEntryType()); + Long commentId = addComment(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser()).getId(); response.add(ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).build()); - actionPerformed = actionPerformed || addRedactionRequest.getStatus().equals(AnnotationStatus.APPROVED); } analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - if (actionPerformed) { + if (addRedactionRequests.stream().anyMatch(BaseManualRequest::isApproved)) { reprocess(dossierId, fileId); } @@ -108,7 +128,19 @@ public class ManualRedactionService { } - private void validateDictionary(AddRedactionRequest addRedactionRequest) { + private void validateDictionaries(ManualRequestWithDictionary addRedactionRequest) { + + if (addRedactionRequest.isAddToDictionary()) { + if (addRedactionRequest.isAddToAllDossiers()) { + // validate add to dossier template dictionaries + dictionaryManagementService.validateAddRemoveToDossierTemplateDictionary(addRedactionRequest.getDossierTemplateTypeId()); + } + validateDictionary(addRedactionRequest); + } + } + + + private void validateDictionary(ManualRequestWithDictionary addRedactionRequest) { try { if (!addRedactionRequest.isForceAddToDictionary() && stopwordService.isStopword(addRedactionRequest.getValue())) { @@ -130,6 +162,10 @@ public class ManualRedactionService { private CommentEntity addComment(String fileId, String annotationId, String comment, String user) { + if (comment == null) { + return null; + } + return commentPersistenceService.insert(CommentEntity.builder() .text(comment) .fileId(fileId) @@ -140,49 +176,6 @@ public class ManualRedactionService { } - private boolean handleAddToDictionary(String fileId, - String annotationId, - String dossierTemplateTypeId, - String value, - AnnotationStatus status, - boolean addToDictionary, - boolean addToAllDossiers, - boolean revert, - String dossierId, - DictionaryEntryType dictionaryEntryType) { - - if (status == AnnotationStatus.APPROVED) { - - if (addToDictionary) { - Set typeIdsOfModifiedDictionaries = new HashSet<>(); - if (revert) { - var addRedactionToRevert = addRedactionPersistenceService.findAddRedaction(fileId, annotationId); - addRedactionToRevert.getTypeIdsOfModifiedDictionaries().forEach(typeId -> { - removeFromDictionary(typeId, value, dossierId, fileId, dictionaryEntryType); - }); - } else { - if (addToAllDossiers) { - var dictionaryEntriesToUnDelete = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplateTypeId, value, dictionaryEntryType); - dictionaryEntriesToUnDelete.forEach(entry -> { - typeIdsOfModifiedDictionaries.add(entry.getTypeId()); - addToDictionary(entry.getTypeId(), value, dossierId, fileId, dictionaryEntryType); - }); - addToDictionary(dossierTemplateTypeId, value, dossierId, fileId, dictionaryEntryType); - typeIdsOfModifiedDictionaries.add(dossierTemplateTypeId); - } else { - addToDictionary(dossierTemplateTypeId + ":" + dossierId, value, dossierId, fileId, dictionaryEntryType); - typeIdsOfModifiedDictionaries.add(dossierTemplateTypeId + ":" + dossierId); - } - addRedactionPersistenceService.updateStatus(fileId, annotationId, status, true, typeIdsOfModifiedDictionaries); - } - return true; - } - addRedactionPersistenceService.updateStatus(fileId, annotationId, status, false, null); - } - return false; - } - - private void reprocess(String dossierId, String fileId) { fileStatusService.setStatusReprocessForManual(dossierId, fileId, true); @@ -237,49 +230,44 @@ public class ManualRedactionService { } }); - for (var removeRedactionRequest : removeRedactionRequests) { + for (RemoveRedactionRequest removeRedactionRequest : removeRedactionRequests) { - if (manualAddRedactionsContains(manualRedactions, removeRedactionRequest.getAnnotationId()) && AnnotationStatus.APPROVED.equals(removeRedactionRequest.getStatus())) { + if (manualAddRedactionsContains(manualRedactions, removeRedactionRequest.getAnnotationId()) && removeRedactionRequest.getStatus().equals(AnnotationStatus.APPROVED)) { log.info("hard delete ManualRedactions for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId()); manualRedactionProviderService.hardDeleteManualRedactions(fileId, removeRedactionRequest.getAnnotationId()); - } else { - - log.info("add removeRedaction for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId()); - var idRemoval = MagicConverter.convert(removeRedactionPersistenceService.insert(fileId, removeRedactionRequest), IdRemoval.class); - - Long commentId = null; - if (removeRedactionRequest.getComment() != null) { - commentId = addComment(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getComment(), removeRedactionRequest.getUser()).getId(); - } - boolean matchingEntryFound = false; - if (!removeRedactionRequest.isRemoveFromDictionary() && AnnotationStatus.APPROVED.equals(removeRedactionRequest.getStatus())) { - try { - getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId()); - matchingEntryFound = true; - } catch (NotFoundException e) { - log.warn("No matching entry found in redaction log for annotation id {}", removeRedactionRequest.getAnnotationId()); - } - - requiresReAnalysis = requiresReAnalysis || matchingEntryFound; - } - - var removedFromDictionary = handleRemoveFromDictionary(redactionLog, - dossier, - fileId, - removeRedactionRequest.getAnnotationId(), - removeRedactionRequest.getStatus(), - removeRedactionRequest.isRemoveFromDictionary(), - removeRedactionRequest.isRemoveFromAllDossiers(), - false); - - if (!matchingEntryFound && !removedFromDictionary && idRemoval.isApproved()) { - removeRedactionPersistenceService.markAsProcessed(idRemoval); - } - - requiresReAnalysis = requiresReAnalysis || removedFromDictionary; - - response.add(ManualAddResponse.builder().annotationId(removeRedactionRequest.getAnnotationId()).commentId(commentId).build()); + requiresReAnalysis = true; + continue; } + + log.info("add removeRedaction for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId()); + IdRemoval idRemoval = MagicConverter.convert(removeRedactionPersistenceService.insert(fileId, removeRedactionRequest), IdRemoval.class); + + Long commentId = addComment(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getComment(), removeRedactionRequest.getUser()).getId(); + boolean matchingEntryFound = false; + if (!removeRedactionRequest.isRemoveFromDictionary() && AnnotationStatus.APPROVED.equals(removeRedactionRequest.getStatus())) { + try { + getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId()); + matchingEntryFound = true; + } catch (NotFoundException e) { + log.warn("No matching entry found in redaction log for annotation id {}", removeRedactionRequest.getAnnotationId()); + } + + requiresReAnalysis = requiresReAnalysis || matchingEntryFound; + } + + + boolean removedFromDictionary = handleRemoveFromDictionary(getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId()), + dossier, + fileId, + removeRedactionRequest); + + if (!matchingEntryFound && !removedFromDictionary && idRemoval.isApproved()) { + removeRedactionPersistenceService.markAsProcessed(idRemoval); + } + + requiresReAnalysis = requiresReAnalysis || removedFromDictionary; + + response.add(ManualAddResponse.builder().annotationId(removeRedactionRequest.getAnnotationId()).commentId(commentId).build()); } if (requiresReAnalysis) { @@ -298,68 +286,67 @@ public class ManualRedactionService { } - private boolean handleRemoveFromDictionary(RedactionLog redactionLog, - DossierEntity dossier, - String fileId, - String annotationId, - AnnotationStatus status, - boolean removeFromDictionary, - boolean removeFromAllDossiers, - boolean revert) { + private boolean revertRemoveFromDictionary(String value, DossierEntity dossier, String fileId, IdRemovalEntity idRemoval) { - if (status == AnnotationStatus.APPROVED) { + String annotationId = idRemoval.getId().getAnnotationId(); - Set typeIdsOfModifiedDictionaries = new HashSet<>(); - - if (removeFromDictionary) { - - RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, annotationId); - - if (revert) { - var idRemovalEntity = removeRedactionPersistenceService.findRemoveRedaction(fileId, annotationId); - idRemovalEntity.getTypeIdsOfModifiedDictionaries().forEach(changedTypeId -> { - addToDictionary(changedTypeId, redactionLogEntry.getValue(), dossier.getId(), fileId, DictionaryEntryType.ENTRY); - }); - } else { - if (removeFromAllDossiers) { - var dictionaryEntriesToRemove = dictionaryManagementService.getAllEntriesInDossierTemplate(toTypeId(redactionLogEntry.getType(), - dossier.getDossierTemplateId()), redactionLogEntry.getValue(), DictionaryEntryType.ENTRY); - dictionaryEntriesToRemove.forEach(entry -> { - typeIdsOfModifiedDictionaries.add(entry.getTypeId()); - removeFromDictionary(entry.getTypeId(), entry.getValue(), dossier.getId(), fileId, DictionaryEntryType.ENTRY); - }); - } else { - typeIdsOfModifiedDictionaries.add(toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId())); - removeFromDictionary(toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId()), - redactionLogEntry.getValue(), - dossier.getId(), - fileId, - DictionaryEntryType.ENTRY); - } - - // This is needed to remove resizeRedactions with addToDictionary. - removeResizeRedactionsWithAddToDictionary(dossier.getDossierTemplateId(), redactionLogEntry.getValue()); - } - - removeRedactionPersistenceService.updateStatus(fileId, annotationId, status, true, typeIdsOfModifiedDictionaries); - return true; - } - removeRedactionPersistenceService.updateStatus(fileId, annotationId, status, false, typeIdsOfModifiedDictionaries); + if (!idRemoval.getStatus().equals(AnnotationStatus.APPROVED)) { + return false; } - return false; + if (idRemoval.isRemoveFromDictionary()) { + removeRedactionPersistenceService.updateStatus(fileId, annotationId, idRemoval.getStatus(), false, Collections.emptySet()); + return false; + } + + idRemoval.getTypeIdsOfModifiedDictionaries().forEach(changedTypeId -> addToDictionary(changedTypeId, value, dossier.getId(), fileId, DictionaryEntryType.ENTRY)); + removeRedactionPersistenceService.updateStatus(fileId, annotationId, idRemoval.getStatus(), true, Collections.emptySet()); + return true; + } + + + private boolean handleRemoveFromDictionary(RedactionLogEntry redactionLogEntry, DossierEntity dossier, String fileId, RemoveRedactionRequest removeRedactionRequest) { + + if (!removeRedactionRequest.isApproved()) { + return false; + } + + if (!removeRedactionRequest.isRemoveFromDictionary()) { + removeRedactionPersistenceService.updateStatus(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getStatus(), false, Collections.emptySet()); + return false; + } + + Set typeIdsOfModifiedDictionaries = new HashSet<>(); + if (removeRedactionRequest.isRemoveFromAllDossiers()) { + var dictionaryEntriesToRemove = dictionaryManagementService.getAllEntriesInDossierTemplate(toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId()), + redactionLogEntry.getValue()); + dictionaryEntriesToRemove.forEach(entry -> { + typeIdsOfModifiedDictionaries.add(entry.getTypeId()); + removeFromDictionary(entry.getTypeId(), entry.getValue(), dossier.getId(), fileId, DictionaryEntryType.ENTRY); + }); + } else { + typeIdsOfModifiedDictionaries.add(toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId())); + removeFromDictionary(toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId()), + redactionLogEntry.getValue(), + dossier.getId(), + fileId, + DictionaryEntryType.ENTRY); + } + + // This is needed to remove resizeRedactions with addToDictionary. + removeResizeRedactionsWithAddToDictionary(dossier.getDossierTemplateId(), redactionLogEntry.getValue()); + + removeRedactionPersistenceService.updateStatus(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getStatus(), true, typeIdsOfModifiedDictionaries); + return true; } private RedactionLogEntry getRedactionLogEntry(RedactionLog redactionLog, String annotationId) { - Optional redactionLogEntryOptional = redactionLog.getRedactionLogEntry().stream().filter(entry -> entry.getId().equals(annotationId)).findFirst(); - - if (redactionLogEntryOptional.isEmpty()) { - throw new NotFoundException("Annotation does not exist in redaction log."); - } - - var redactionLogEntry = redactionLogEntryOptional.get(); - return redactionLogEntry; + return redactionLog.getRedactionLogEntry() + .stream() + .filter(entry -> entry.getId().equals(annotationId)) + .findFirst() + .orElseThrow(() -> new NotFoundException("Annotation does not exist in redaction log.")); } @@ -381,21 +368,18 @@ public class ManualRedactionService { var response = new ArrayList(); dossierPersistenceService.getAndValidateDossier(dossierId); - var actionPerformed = false; + var requiresReanalysis = false; for (var forceRedactionRequest : forceRedactionRequests) { forceRedactionPersistenceService.insert(fileId, forceRedactionRequest); - Long commentId = null; - if (forceRedactionRequest.getComment() != null) { + Long commentId = addComment(fileId, forceRedactionRequest.getAnnotationId(), forceRedactionRequest.getComment(), forceRedactionRequest.getUser()).getId(); - commentId = addComment(fileId, forceRedactionRequest.getAnnotationId(), forceRedactionRequest.getComment(), forceRedactionRequest.getUser()).getId(); - } - actionPerformed = actionPerformed || forceRedactionRequest.getStatus().equals(AnnotationStatus.APPROVED); + requiresReanalysis = requiresReanalysis || forceRedactionRequest.isApproved(); response.add(ManualAddResponse.builder().annotationId(forceRedactionRequest.getAnnotationId()).commentId(commentId).build()); } - if (actionPerformed) { + if (requiresReanalysis) { reprocess(dossierId, fileId); } @@ -414,11 +398,7 @@ public class ManualRedactionService { for (var legalBasisChangeRequest : legalBasisChangeRequests) { legalBasisChangePersistenceService.insert(fileId, legalBasisChangeRequest); - Long commentId = null; - if (legalBasisChangeRequest.getComment() != null) { - - commentId = addComment(fileId, legalBasisChangeRequest.getAnnotationId(), legalBasisChangeRequest.getComment(), legalBasisChangeRequest.getUser()).getId(); - } + Long commentId = addComment(fileId, legalBasisChangeRequest.getAnnotationId(), legalBasisChangeRequest.getComment(), legalBasisChangeRequest.getUser()).getId(); response.add(ManualAddResponse.builder().annotationId(legalBasisChangeRequest.getAnnotationId()).commentId(commentId).build()); } @@ -429,27 +409,20 @@ public class ManualRedactionService { @Transactional - public List addImageRecategorization(String dossierId, String fileId, List imageRecategorizationRequests) { + public List addRecategorization(String dossierId, String fileId, List recategorizationRequests) { var response = new ArrayList(); var actionPerformed = false; dossierPersistenceService.getAndValidateDossier(dossierId); - for (var imageRecategorizationRequest : imageRecategorizationRequests) { - recategorizationPersistenceService.insert(fileId, imageRecategorizationRequest); + for (var recategorizationRequest : recategorizationRequests) { + recategorizationPersistenceService.insert(fileId, recategorizationRequest); - Long commentId = null; - if (imageRecategorizationRequest.getComment() != null) { + Long commentId = addComment(fileId, recategorizationRequest.getAnnotationId(), recategorizationRequest.getComment(), recategorizationRequest.getUser()).getId(); - commentId = addComment(fileId, - imageRecategorizationRequest.getAnnotationId(), - imageRecategorizationRequest.getComment(), - imageRecategorizationRequest.getUser()).getId(); - } + actionPerformed = actionPerformed || recategorizationRequest.getStatus().equals(AnnotationStatus.APPROVED); - actionPerformed = actionPerformed || imageRecategorizationRequest.getStatus().equals(AnnotationStatus.APPROVED); - - response.add(ManualAddResponse.builder().annotationId(imageRecategorizationRequest.getAnnotationId()).commentId(commentId).build()); + response.add(ManualAddResponse.builder().annotationId(recategorizationRequest.getAnnotationId()).commentId(commentId).build()); } if (actionPerformed) { reprocess(dossierId, fileId); @@ -463,7 +436,7 @@ public class ManualRedactionService { public CommentEntity addComment(String fileId, String annotationId, CommentRequest commentRequest) { - var createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser()); + CommentEntity createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser()); fileStatusPersistenceService.updateHasComments(fileId, true); @@ -475,24 +448,17 @@ public class ManualRedactionService { public void deleteAddRedaction(String dossierId, String fileId, List annotationIds) { var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); - var actionPerformed = false; + var changedDictionary = false; - for (var annotationId : annotationIds) { - var addRedaction = getAddRedaction(fileId, annotationId); - actionPerformed = actionPerformed || handleAddToDictionary(fileId, - annotationId, - addRedaction.getTypeId(), - addRedaction.getValue(), - addRedaction.getStatus(), - addRedaction.isAddToDictionary(), - addRedaction.isAddToAllDossiers(), - true, - dossier.getId(), - addRedaction.getDictionaryEntryType()); + for (String annotationId : annotationIds) { + ManualRedactionEntryEntity addRedaction = getAddRedaction(fileId, annotationId); + + changedDictionary = manualRedactionDictionaryUpdateHandler.revertAddToDictionary(fileId, dossier.getId(), addRedaction) || changedDictionary; + addRedactionPersistenceService.updateStatus(fileId, annotationId, AnnotationStatus.APPROVED, false, null); addRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); } - if (actionPerformed) { + if (changedDictionary) { reprocess(dossierId, fileId); } @@ -504,27 +470,20 @@ public class ManualRedactionService { public void deleteRemoveRedaction(String dossierId, String fileId, List annotationIds) { var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); - var actionPerformed = false; + var requiresReanalysis = false; RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId, true, true); - for (var annotationId : annotationIds) { + for (String annotationId : annotationIds) { - var removeRedaction = getRemoveRedaction(fileId, annotationId); + IdRemovalEntity removeRedaction = getRemoveRedaction(fileId, annotationId); + String originalValue = getRedactionLogEntry(redactionLog, annotationId).getValue(); + boolean dictionaryChanged = revertRemoveFromDictionary(originalValue, dossier, fileId, removeRedaction); - var removedFromDictionary = handleRemoveFromDictionary(redactionLog, - dossier, - fileId, - annotationId, - removeRedaction.getStatus(), - removeRedaction.isRemoveFromDictionary(), - removeRedaction.isRemoveFromAllDossiers(), - true); - - actionPerformed = actionPerformed || removedFromDictionary; + requiresReanalysis = requiresReanalysis || dictionaryChanged; removeRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); } - if (actionPerformed) { + if (requiresReanalysis) { reprocess(dossierId, fileId); } @@ -612,7 +571,7 @@ public class ManualRedactionService { @Transactional public List addResizeRedaction(String dossierId, String fileId, List resizeRedactionRequests) { - var response = new ArrayList(); + List response = new ArrayList<>(); RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId, true, true); @@ -621,14 +580,14 @@ public class ManualRedactionService { var resizeRedaction = resizeRedactionPersistenceService.insert(fileId, resizeRedactionRequest); if (resizeRedactionRequest.getComment() != null) { - var commentId = addComment(fileId, resizeRedactionRequest.getAnnotationId(), resizeRedactionRequest.getComment(), resizeRedactionRequest.getUser()).getId(); + Long commentId = addComment(fileId, resizeRedactionRequest.getAnnotationId(), resizeRedactionRequest.getComment(), resizeRedactionRequest.getUser()).getId(); response.add(ManualAddResponse.builder().annotationId(resizeRedactionRequest.getAnnotationId()).commentId(commentId).build()); } updateDictionaryForResizeRedactions(dossierId, fileId, resizeRedaction, redactionLog); } - if (resizeRedactionRequests.stream().anyMatch(resize -> AnnotationStatus.APPROVED.equals(resize.getStatus()))) { + if (resizeRedactionRequests.stream().anyMatch(BaseManualRequest::isApproved)) { reprocess(dossierId, fileId); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java index 3c96b3032..632b6d3cf 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java @@ -13,7 +13,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.annotati import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.ImageRecategorizationRepository; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ImageRecategorizationRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RecategorizationRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -26,11 +26,11 @@ public class ImageRecategorizationPersistenceService { private final ImageRecategorizationRepository imageRecategorizationRepository; - public void insert(String fileId, ImageRecategorizationRequest imageRecategorizationRequest) { + public void insert(String fileId, RecategorizationRequest recategorizationRequest) { ManualImageRecategorizationEntity manualImageRecategorization = new ManualImageRecategorizationEntity(); - manualImageRecategorization.setId(new AnnotationEntityId(imageRecategorizationRequest.getAnnotationId(), fileId)); - BeanUtils.copyProperties(imageRecategorizationRequest, manualImageRecategorization); + manualImageRecategorization.setId(new AnnotationEntityId(recategorizationRequest.getAnnotationId(), fileId)); + BeanUtils.copyProperties(recategorizationRequest, manualImageRecategorization); manualImageRecategorization.setRequestDate(OffsetDateTime.now()); imageRecategorizationRepository.saveAndFlush(manualImageRecategorization); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/RedactionLogMergeService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/RedactionLogMergeService.java index 38dc7672a..31f11bce4 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/RedactionLogMergeService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/RedactionLogMergeService.java @@ -187,7 +187,7 @@ public class RedactionLogMergeService { Object item = mrw.getItem(); if (item instanceof ManualImageRecategorization) { var imageRecategorization = (ManualImageRecategorization) item; - processManualImageRecategorization(redactionLogEntry, types, colors, imageRecategorization); + processManualRecategorization(redactionLogEntry, types, colors, imageRecategorization); } if (item instanceof IdRemoval) { @@ -215,13 +215,12 @@ public class RedactionLogMergeService { } - private void processManualImageRecategorization(RedactionLogEntry redactionLogEntry, List types, Colors colors, ManualImageRecategorization imageRecategorization) { + private void processManualRecategorization(RedactionLogEntry redactionLogEntry, List types, Colors colors, ManualImageRecategorization imageRecategorization) { String manualOverrideReason = null; if (imageRecategorization.getStatus().equals(AnnotationStatus.APPROVED)) { redactionLogEntry.setType(imageRecategorization.getType()); - redactionLogEntry.setSection("Image:" + redactionLogEntry.getType()); if (isHint(types, imageRecategorization.getType())) { redactionLogEntry.setRedacted(false); 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 2f2ebdb01..fbf87c741 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 @@ -14,8 +14,13 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp 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.dossier.file.ProcessingStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; -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.*; +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; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; + import feign.FeignException; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; @@ -329,7 +334,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest { var addRedaction = manualRedactionClient.addRedactionBulk(dossierId, fileId, - Set.of(AddRedactionRequest.builder() + Set.of(AddRedactionRequestModel.builder() .addToDictionary(true) .type(type.getType()) .addToAllDossiers(true) @@ -340,16 +345,16 @@ public class FileTest extends AbstractPersistenceServerServiceTest { .build())).iterator().next(); manualRedactionClient.removeRedactionBulk(dossierId, fileId, - Set.of(RemoveRedactionRequest.builder().annotationId(addRedaction.getAnnotationId()).comment("comment").removeFromDictionary(false).build())); + Set.of(RemoveRedactionRequestModel.builder().annotationId(addRedaction.getAnnotationId()).comment("comment").removeFromDictionary(false).build())); manualRedactionClient.forceRedactionBulk(dossierId, fileId, - Set.of(ForceRedactionRequest.builder().annotationId("forceRedactionAnnotation").comment("comment").legalBasis("1").build())); + Set.of(ForceRedactionRequestModel.builder().annotationId("forceRedactionAnnotation").comment("comment").legalBasis("1").build())); manualRedactionClient.legalBasisChangeBulk(dossierId, fileId, - Set.of(LegalBasisChangeRequest.builder().annotationId("legalBasisChangeAnnotation").comment("comment").legalBasis("1").build())); - manualRedactionClient.recategorizeImageBulk(dossierId, + Set.of(LegalBasisChangeRequestModel.builder().annotationId("legalBasisChangeAnnotation").comment("comment").legalBasis("1").build())); + manualRedactionClient.recategorizeBulk(dossierId, fileId, - Set.of(ImageRecategorizationRequest.builder().annotationId("imageRecategorizationAnnotation").comment("comment").type("new-type").build())); + Set.of(RecategorizationRequestModel.builder().annotationId("imageRecategorizationAnnotation").comment("comment").type("new-type").build())); var loadedFile = fileClient.getFileStatus(dossierId, fileId); @@ -396,10 +401,10 @@ public class FileTest extends AbstractPersistenceServerServiceTest { var addRedaction = manualRedactionClient.addRedactionBulk(dossierId, fileId, - Set.of(AddRedactionRequest.builder() + Set.of(AddRedactionRequestModel.builder() .addToDictionary(true) .addToAllDossiers(true) - .comment(new AddCommentRequest("comment")) + .comment(new AddCommentRequestModel("comment")) .type(type.getType()) .reason("1") .value("test") 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 da817ecf5..e6f9696fb 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 @@ -16,9 +16,9 @@ import com.iqser.red.service.persistence.management.v1.processor.service.redacti 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.AddRedactionRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequest; +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.RemoveRedactionRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import feign.FeignException; @@ -110,7 +110,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { Assertions.assertThrows(FeignException.Forbidden.class, () -> manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), - Set.of(RemoveRedactionRequest.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())));//.get(0); + Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())));//.get(0); var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null); assertThat(dossierTemplateDictionary.getEntries().size()).isZero(); @@ -131,7 +131,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.addRedactionBulk(dossier.getId(), file.getId(), - Set.of(AddRedactionRequest.builder() + Set.of(AddRedactionRequestModel.builder() .positions(List.of(Rectangle.builder().topLeftY(1).topLeftX(1).height(1).width(1).build())) .section("section test") .addToDictionary(true) @@ -166,7 +166,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.addRedactionBulk(dossier.getId(), file.getId(), - Set.of(AddRedactionRequest.builder() + Set.of(AddRedactionRequestModel.builder() .positions(List.of(Rectangle.builder().topLeftY(1).topLeftX(1).height(1).width(1).build())) .section("section test") .addToDictionary(true) @@ -201,7 +201,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.addRedactionBulk(dossier.getId(), file.getId(), - Set.of(AddRedactionRequest.builder() + Set.of(AddRedactionRequestModel.builder() .positions(List.of(Rectangle.builder().topLeftY(1).topLeftX(1).height(1).width(1).build())) .section("section test") .addToDictionary(true) @@ -258,7 +258,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), - Set.of(RemoveRedactionRequest.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())).get(0); + Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())).get(0); dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Darth Vader"); @@ -306,7 +306,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), - Set.of(RemoveRedactionRequest.builder().annotationId("AnnotationId").removeFromDictionary(true).build())).get(0); + Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).build())).get(0); var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null); @@ -347,7 +347,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), - Set.of(RemoveRedactionRequest.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())).get(0); + Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())).get(0); var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null); assertThat(dossierDictionary.getEntries().size()).isEqualTo(1); @@ -375,7 +375,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var userId = userProvider.getUserId(); - var redactionDos = AddRedactionRequest.builder() + var redactionDos = AddRedactionRequestModel.builder() .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build())) .section("section test") .addToDictionary(true) @@ -389,7 +389,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .sourceId("SourceId") .build(); - var redactionDosTempDict = AddRedactionRequest.builder() + var redactionDosTempDict = AddRedactionRequestModel.builder() .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build())) .section("section test") .addToDictionary(true) @@ -449,7 +449,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2); // resize redaction in dossier 1 - var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequest.builder() + var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder() .annotationId(addRedactions.get(0).getAnnotationId()) .comment("resized dossier redaction") .value("test redaction in dossier dictionary") @@ -524,7 +524,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var userId = userProvider.getUserId(); - var redactionDos = AddRedactionRequest.builder() + var redactionDos = AddRedactionRequestModel.builder() .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build())) .section("section test") .addToDictionary(true) @@ -538,7 +538,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .sourceId("SourceId") .build(); - var redactionDosTempDict = AddRedactionRequest.builder() + var redactionDosTempDict = AddRedactionRequestModel.builder() .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build())) .section("section test") .addToDictionary(true) @@ -598,7 +598,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2); // resize redaction in dossier 1 - var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequest.builder() + var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder() .annotationId(addRedactions.get(0).getAnnotationId()) .comment("resized dossier redaction") .value("test redaction in dossier") @@ -676,7 +676,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var userId = userProvider.getUserId(); - var redactionDos = AddRedactionRequest.builder() + var redactionDos = AddRedactionRequestModel.builder() .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build())) .section("section test") .addToDictionary(true) @@ -690,7 +690,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .sourceId("SourceId") .build(); - var redactionDosTempDict = AddRedactionRequest.builder() + var redactionDosTempDict = AddRedactionRequestModel.builder() .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build())) .section("section test") .addToDictionary(true) @@ -749,7 +749,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2); // resize redaction in dossier dict - var resizeRedactionDosTemp = ResizeRedactionRequest.builder() + var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder() .annotationId(addRedactions.get(1).getAnnotationId()) .comment("resized dossier template redaction") .value("test redaction in dossier template dictionary") @@ -824,7 +824,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var userId = userProvider.getUserId(); - var redactionDos = AddRedactionRequest.builder() + var redactionDos = AddRedactionRequestModel.builder() .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build())) .section("section test") .addToDictionary(true) @@ -838,7 +838,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .sourceId("SourceId") .build(); - var redactionDosTempDict = AddRedactionRequest.builder() + var redactionDosTempDict = AddRedactionRequestModel.builder() .positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build())) .section("section test") .addToDictionary(true) @@ -897,7 +897,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2); // resize redaction in dossier dict - var resizeRedactionDosTemp = ResizeRedactionRequest.builder() + var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder() .annotationId(addRedactions.get(1).getAnnotationId()) .comment("resized dossier template redaction") .value("test redaction in dossier template") 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/AddRedactionRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AddRedactionRequest.java index 3d7f37771..7ee98a327 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AddRedactionRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AddRedactionRequest.java @@ -14,7 +14,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class AddRedactionRequest { +public class AddRedactionRequest implements ManualRequestWithDictionary { private String user; private String dossierTemplateTypeId; 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/BaseManualRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/BaseManualRequest.java new file mode 100644 index 000000000..675df57e1 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/BaseManualRequest.java @@ -0,0 +1,13 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations; + +public interface BaseManualRequest { + + AnnotationStatus getStatus(); + + + default boolean isApproved() { + + return getStatus().equals(AnnotationStatus.APPROVED); + } + +} 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/ForceRedactionRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ForceRedactionRequest.java index 5e0cdc677..c84ff57c2 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ForceRedactionRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ForceRedactionRequest.java @@ -9,7 +9,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class ForceRedactionRequest { +public class ForceRedactionRequest implements BaseManualRequest { private String annotationId; private String user; 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/ImageRecategorizationRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ImageRecategorizationRequest.java deleted file mode 100644 index cf31c02e8..000000000 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ImageRecategorizationRequest.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class ImageRecategorizationRequest { - - private String annotationId; - private String user; - private AnnotationStatus status; - private String typeId; - private String comment; - private int page; - -} 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/ManualRequestWithDictionary.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithDictionary.java new file mode 100644 index 000000000..476f23113 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithDictionary.java @@ -0,0 +1,14 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations; + +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; + +public interface ManualRequestWithDictionary extends BaseManualRequest{ + + String getValue(); + boolean isAddToDictionary(); + boolean isAddToAllDossiers(); + boolean isForceAddToDictionary(); + String getDossierTemplateTypeId(); + DictionaryEntryType getDictionaryEntryType(); + +} 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/RecategorizationRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RecategorizationRequest.java new file mode 100644 index 000000000..43d234829 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RecategorizationRequest.java @@ -0,0 +1,44 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations; + +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE) +public class RecategorizationRequest implements ManualRequestWithDictionary { + + String annotationId; + String user; + AnnotationStatus status; + String typeId; + String comment; + int page; + String value; + boolean addToDictionary; + boolean addToAllDossiers; + private DictionaryEntryType dictionaryEntryType; + + + @Override + public boolean isForceAddToDictionary() { + + return true; + } + + + @Override + public String getDossierTemplateTypeId() { + + return typeId; + } + +} 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/RemoveRedactionRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RemoveRedactionRequest.java index eb94b5453..fbdf4b014 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RemoveRedactionRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RemoveRedactionRequest.java @@ -9,7 +9,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class RemoveRedactionRequest { +public class RemoveRedactionRequest implements BaseManualRequest{ private String annotationId; private String user; 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/ResizeRedactionRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ResizeRedactionRequest.java index 21ff7f76b..ff3df9588 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ResizeRedactionRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ResizeRedactionRequest.java @@ -12,7 +12,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class ResizeRedactionRequest { +public class ResizeRedactionRequest implements BaseManualRequest{ private String annotationId; private String user; 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/AddCommentRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/AddCommentRequestModel.java similarity index 89% rename from persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/AddCommentRequest.java rename to persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/AddCommentRequestModel.java index 02d411a70..70a056b51 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/AddCommentRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/AddCommentRequestModel.java @@ -10,7 +10,7 @@ import lombok.NonNull; @Builder @AllArgsConstructor @NoArgsConstructor -public class AddCommentRequest { +public class AddCommentRequestModel { @NonNull private String text; 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/AddRedactionRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/AddRedactionRequestModel.java similarity index 92% rename from persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/AddRedactionRequest.java rename to persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/AddRedactionRequestModel.java index 39186cd13..801dc95d1 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/AddRedactionRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/AddRedactionRequestModel.java @@ -16,7 +16,7 @@ import lombok.NonNull; @Builder @AllArgsConstructor @NoArgsConstructor -public class AddRedactionRequest { +public class AddRedactionRequestModel { @NonNull private String type; @@ -36,7 +36,7 @@ public class AddRedactionRequest { @Builder.Default private List positions = new ArrayList<>(); - private AddCommentRequest comment; + private AddCommentRequestModel comment; private boolean forceAddToDictionary; 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/ApproveRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ApproveRequestModel.java similarity index 88% rename from persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ApproveRequest.java rename to persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ApproveRequestModel.java index 012e8bedb..7e2face01 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ApproveRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ApproveRequestModel.java @@ -7,7 +7,7 @@ import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor -public class ApproveRequest { +public class ApproveRequestModel { private boolean addOrRemoveFromDictionary; 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/ForceRedactionRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ForceRedactionRequestModel.java similarity index 90% rename from persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ForceRedactionRequest.java rename to persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ForceRedactionRequestModel.java index bfec48c96..8078eb6e1 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ForceRedactionRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ForceRedactionRequestModel.java @@ -10,7 +10,7 @@ import lombok.NonNull; @Builder @AllArgsConstructor @NoArgsConstructor -public class ForceRedactionRequest { +public class ForceRedactionRequestModel { @NonNull private String annotationId; 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/ImageRecategorizationRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ImageRecategorizationRequest.java deleted file mode 100644 index d5a5ab696..000000000 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ImageRecategorizationRequest.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.iqser.red.service.persistence.service.v1.api.shared.model.manual; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class ImageRecategorizationRequest { - - private String annotationId; - private String type; - private String comment; - -} 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/LegalBasisChangeRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/LegalBasisChangeRequestModel.java similarity index 90% rename from persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/LegalBasisChangeRequest.java rename to persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/LegalBasisChangeRequestModel.java index 22a921949..5691ee273 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/LegalBasisChangeRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/LegalBasisChangeRequestModel.java @@ -10,7 +10,7 @@ import lombok.NonNull; @Builder @AllArgsConstructor @NoArgsConstructor -public class LegalBasisChangeRequest { +public class LegalBasisChangeRequestModel { @NonNull private String annotationId; 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/ManualRedactionWrapper.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ManualRedactionWrapperModel.java similarity index 70% rename from persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ManualRedactionWrapper.java rename to persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ManualRedactionWrapperModel.java index cb6f603bf..8c2da4973 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ManualRedactionWrapper.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/manual/ManualRedactionWrapperModel.java @@ -7,7 +7,7 @@ import lombok.Data; @Data @AllArgsConstructor -public class ManualRedactionWrapper implements Comparable { +public class ManualRedactionWrapperModel implements Comparable { private String id; private OffsetDateTime date; @@ -15,7 +15,7 @@ public class ManualRedactionWrapper implements Comparable Date: Tue, 29 Aug 2023 15:20:04 +0200 Subject: [PATCH 2/7] RED-7317: add getComment Endpoint * moved manual redaction undo code --- .../controller/ManualRedactionController.java | 185 +------------ .../resource/ManualRedactionResource.java | 11 +- .../ManualRedactionService.java | 90 ++++--- .../ManualRedactionUndoService.java | 247 ++++++++++++++++++ .../shared/model/annotations/Comments.java | 19 ++ 5 files changed, 346 insertions(+), 206 deletions(-) create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comments.java 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 b8a575214..4ce41002b 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 @@ -8,8 +8,6 @@ import static com.iqser.red.service.persistence.management.v1.processor.roles.Ac import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId; import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -20,10 +18,10 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService; import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService; import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService; +import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionUndoService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; import com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource; import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; @@ -31,20 +29,14 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResp 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.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualImageRecategorization; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange; -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.annotations.entitymapped.ManualResizeRedaction; import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest; 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; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ManualRedactionWrapperModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel; @@ -62,182 +54,20 @@ public class ManualRedactionController implements ManualRedactionResource { private static final String DOSSIER_ID = "dossierId"; private static final String ANNOTATION_ID = "annotationId"; private final ManualRedactionService manualRedactionService; + private final ManualRedactionUndoService manualRedactionUndoService; private final DossierManagementService dossierManagementService; private final AuditPersistenceService auditPersistenceService; private final AccessControlService accessControlService; - private ManualRedactionWrapperModel getLatestManualRedactionForAnnotationId(ManualRedactions manualRedactions, String annotationId) { - - final List manualRedactionWrappers = new ArrayList<>(); - - manualRedactions.getEntriesToAdd() - .stream() - .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); - - manualRedactions.getImageRecategorization() - .stream() - .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); - - manualRedactions.getIdsToRemove() - .stream() - .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); - - manualRedactions.getForceRedactions() - .stream() - .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); - - manualRedactions.getLegalBasisChanges() - .stream() - .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); - - manualRedactions.getResizeRedactions() - .stream() - .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); - - var sortedManualRedactionWrappers = manualRedactionWrappers.stream() - .sorted(Comparator.comparing(ManualRedactionWrapperModel::getDate, Comparator.nullsLast(Comparator.reverseOrder()))) - .collect(Collectors.toList()); - - return sortedManualRedactionWrappers.isEmpty() ? null : sortedManualRedactionWrappers.get(0); - } - - @Override @PreAuthorize("hasAuthority('" + DELETE_MANUAL_REDACTION + "')") public void undo(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody Set annotationIds) { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsApprover(dossierId); + manualRedactionUndoService.undo(dossierId, fileId, annotationIds); - ManualRedactions manualRedactions = manualRedactionService.getManualRedactions(fileId); - - Map manualRedactionWrappers = getLatestManualRedactionsForAnnotationIds(manualRedactions, annotationIds); - - if (manualRedactionWrappers.isEmpty()) { - throw new NotFoundException(String.format("ManualRedaction with annotationIds %s could not be found.", annotationIds)); - } - - List manualRedactionEntries = manualRedactionWrappers.values() - .stream() - .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualRedactionEntry) - .map(ManualRedactionWrapperModel::getId) - .collect(Collectors.toList()); - if (!manualRedactionEntries.isEmpty()) { - manualRedactionService.deleteAddRedaction(dossierId, fileId, manualRedactionEntries); - manualRedactionEntries.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("Undo of manual add redaction was done.") - .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) - .build())); - } - - List idRemovals = manualRedactionWrappers.values() - .stream() - .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof IdRemoval) - .map(ManualRedactionWrapperModel::getId) - .collect(Collectors.toList()); - if (!idRemovals.isEmpty()) { - - manualRedactionService.deleteRemoveRedaction(dossierId, fileId, idRemovals); - idRemovals.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("Undo of manual remove redaction was done.") - .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) - .build())); - } - - List manualForceRedactions = manualRedactionWrappers.values() - .stream() - .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualForceRedaction) - .map(ManualRedactionWrapperModel::getId) - .collect(Collectors.toList()); - if (!manualForceRedactions.isEmpty()) { - - manualRedactionService.deleteForceRedaction(dossierId, fileId, manualForceRedactions); - manualForceRedactions.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("Undo of manual force redaction was done.") - .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) - .build())); - } - - List manualImageRecategorizations = manualRedactionWrappers.values() - .stream() - .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualImageRecategorization) - .map(ManualRedactionWrapperModel::getId) - .collect(Collectors.toList()); - if (!manualImageRecategorizations.isEmpty()) { - - manualRedactionService.deleteImageRecategorization(dossierId, fileId, manualImageRecategorizations); - manualImageRecategorizations.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("Undo of manual image recategorization was done.") - .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) - .build())); - } - - List manualLegalBasisChanges = manualRedactionWrappers.values() - .stream() - .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualLegalBasisChange) - .map(ManualRedactionWrapperModel::getId) - .collect(Collectors.toList()); - if (!manualLegalBasisChanges.isEmpty()) { - - manualRedactionService.deleteLegalBasisChange(dossierId, fileId, manualLegalBasisChanges); - manualLegalBasisChanges.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("Undo of legal basis change was done.") - .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) - .build())); - } - - List manualResizeRedactions = manualRedactionWrappers.values() - .stream() - .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualResizeRedaction) - .map(ManualRedactionWrapperModel::getId) - .collect(Collectors.toList()); - if (!manualResizeRedactions.isEmpty()) { - - manualRedactionService.deleteResizeRedaction(dossierId, fileId, manualResizeRedactions); - manualResizeRedactions.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("Undo of manual resize redaction was done.") - .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) - .build())); - } - } - - - private Map getLatestManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set annotationIds) { - - Map result = new HashMap<>(); - annotationIds.forEach(annotationId -> { - var last = getLatestManualRedactionForAnnotationId(manualRedactions, annotationId); - if (last != null) { - result.put(annotationId, last); - } - }); - - return result; } @@ -270,6 +100,13 @@ public class ManualRedactionController implements ManualRedactionResource { return manualRedactionService.getManualRedactions(fileId); } + @Override + @PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')") + public Comments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { + + return manualRedactionService.getComments(fileId); + } + @Override @PreAuthorize("hasAuthority('" + ADD_COMMENT + "')") diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java index 5cd1ff519..93904a9cd 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java @@ -13,13 +13,14 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; 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; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel; @@ -132,4 +133,12 @@ public interface ManualRedactionResource { @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId); + + + @ResponseStatus(value = HttpStatus.OK) + @GetMapping(value = MANUAL_REDACTION_REST_PATH + "/comments" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Returns the comments for a specific file", description = "None") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) + Comments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId); + } 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 01b69b8be..5310ed49c 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 @@ -9,7 +9,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -45,7 +47,9 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist 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.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.BaseManualRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; 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.ManualAddResponse; @@ -55,6 +59,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.annotations.entitymapped.IdRemoval; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; 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.redactionlog.RedactionLog; @@ -104,16 +109,10 @@ public class ManualRedactionService { String annotationId = hashFunction.hashString(fileId + addRedactionRequest, StandardCharsets.UTF_8).toString(); - if (addRedactionRequest.isAddToDictionary()) { - Set typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.handleAddToDictionary(fileId, dossierId, addRedactionRequest); - addRedactionPersistenceService.updateStatus(fileId, annotationId, addRedactionRequest.getStatus(), true, typeIdsOfModifiedDictionaries); - } else { - addRedactionPersistenceService.updateStatus(fileId, annotationId, addRedactionRequest.getStatus(), false, null); - } - addRedactionPersistenceService.insert(fileId, annotationId, addRedactionRequest); + manualRedactionDictionaryUpdateHandler.handleAddToDictionary(fileId, annotationId, addRedactionRequest); - Long commentId = addComment(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser()).getId(); + Long commentId = addCommentAndGetId(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser()); response.add(ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).build()); } @@ -160,6 +159,15 @@ public class ManualRedactionService { } + private Long addCommentAndGetId(String fileId, String annotationId, String comment, String user) { + + if (comment == null) { + return null; + } + return addComment(fileId, annotationId, comment, user).getId(); + } + + private CommentEntity addComment(String fileId, String annotationId, String comment, String user) { if (comment == null) { @@ -242,7 +250,7 @@ public class ManualRedactionService { log.info("add removeRedaction for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId()); IdRemoval idRemoval = MagicConverter.convert(removeRedactionPersistenceService.insert(fileId, removeRedactionRequest), IdRemoval.class); - Long commentId = addComment(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getComment(), removeRedactionRequest.getUser()).getId(); + Long commentId = addCommentAndGetId(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getComment(), removeRedactionRequest.getUser()); boolean matchingEntryFound = false; if (!removeRedactionRequest.isRemoveFromDictionary() && AnnotationStatus.APPROVED.equals(removeRedactionRequest.getStatus())) { try { @@ -255,7 +263,6 @@ public class ManualRedactionService { requiresReAnalysis = requiresReAnalysis || matchingEntryFound; } - boolean removedFromDictionary = handleRemoveFromDictionary(getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId()), dossier, fileId, @@ -293,7 +300,7 @@ public class ManualRedactionService { if (!idRemoval.getStatus().equals(AnnotationStatus.APPROVED)) { return false; } - if (idRemoval.isRemoveFromDictionary()) { + if (!idRemoval.isRemoveFromDictionary()) { removeRedactionPersistenceService.updateStatus(fileId, annotationId, idRemoval.getStatus(), false, Collections.emptySet()); return false; } @@ -373,7 +380,7 @@ public class ManualRedactionService { for (var forceRedactionRequest : forceRedactionRequests) { forceRedactionPersistenceService.insert(fileId, forceRedactionRequest); - Long commentId = addComment(fileId, forceRedactionRequest.getAnnotationId(), forceRedactionRequest.getComment(), forceRedactionRequest.getUser()).getId(); + Long commentId = addCommentAndGetId(fileId, forceRedactionRequest.getAnnotationId(), forceRedactionRequest.getComment(), forceRedactionRequest.getUser()); requiresReanalysis = requiresReanalysis || forceRedactionRequest.isApproved(); response.add(ManualAddResponse.builder().annotationId(forceRedactionRequest.getAnnotationId()).commentId(commentId).build()); @@ -398,7 +405,7 @@ public class ManualRedactionService { for (var legalBasisChangeRequest : legalBasisChangeRequests) { legalBasisChangePersistenceService.insert(fileId, legalBasisChangeRequest); - Long commentId = addComment(fileId, legalBasisChangeRequest.getAnnotationId(), legalBasisChangeRequest.getComment(), legalBasisChangeRequest.getUser()).getId(); + Long commentId = addCommentAndGetId(fileId, legalBasisChangeRequest.getAnnotationId(), legalBasisChangeRequest.getComment(), legalBasisChangeRequest.getUser()); response.add(ManualAddResponse.builder().annotationId(legalBasisChangeRequest.getAnnotationId()).commentId(commentId).build()); } @@ -412,19 +419,19 @@ public class ManualRedactionService { public List addRecategorization(String dossierId, String fileId, List recategorizationRequests) { var response = new ArrayList(); - var actionPerformed = false; + var requiresReanalysis = false; dossierPersistenceService.getAndValidateDossier(dossierId); for (var recategorizationRequest : recategorizationRequests) { recategorizationPersistenceService.insert(fileId, recategorizationRequest); - Long commentId = addComment(fileId, recategorizationRequest.getAnnotationId(), recategorizationRequest.getComment(), recategorizationRequest.getUser()).getId(); + Long commentId = addCommentAndGetId(fileId, recategorizationRequest.getAnnotationId(), recategorizationRequest.getComment(), recategorizationRequest.getUser()); - actionPerformed = actionPerformed || recategorizationRequest.getStatus().equals(AnnotationStatus.APPROVED); + requiresReanalysis = requiresReanalysis || recategorizationRequest.getStatus().equals(AnnotationStatus.APPROVED); response.add(ManualAddResponse.builder().annotationId(recategorizationRequest.getAnnotationId()).commentId(commentId).build()); } - if (actionPerformed) { + if (requiresReanalysis) { reprocess(dossierId, fileId); } @@ -448,17 +455,19 @@ public class ManualRedactionService { public void deleteAddRedaction(String dossierId, String fileId, List annotationIds) { var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); - var changedDictionary = false; + var requiresReanalysis = false; for (String annotationId : annotationIds) { + ManualRedactionEntryEntity addRedaction = getAddRedaction(fileId, annotationId); - changedDictionary = manualRedactionDictionaryUpdateHandler.revertAddToDictionary(fileId, dossier.getId(), addRedaction) || changedDictionary; + boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertAddToDictionary(fileId, dossier.getId(), addRedaction); + requiresReanalysis = requiresReanalysis || dictionaryChanged; addRedactionPersistenceService.updateStatus(fileId, annotationId, AnnotationStatus.APPROVED, false, null); addRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); } - if (changedDictionary) { + if (requiresReanalysis) { reprocess(dossierId, fileId); } @@ -471,7 +480,7 @@ public class ManualRedactionService { var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); var requiresReanalysis = false; - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId, true, true); + RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); for (String annotationId : annotationIds) { @@ -522,38 +531,48 @@ public class ManualRedactionService { @Transactional - public void deleteImageRecategorization(String dossierId, String fileId, List annotationIds) { + public void deleteRecategorization(String dossierId, String fileId, List annotationIds) { - var actionPerformed = false; + var requiresReanalysis = false; for (var annotationId : annotationIds) { - var imageRecategorization = getImageRecategorization(fileId, annotationId); + var imageRecategorization = getRecategorization(fileId, annotationId); recategorizationPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - actionPerformed = actionPerformed || !AnnotationStatus.REQUESTED.equals(imageRecategorization.getStatus()); + requiresReanalysis = requiresReanalysis || !AnnotationStatus.REQUESTED.equals(imageRecategorization.getStatus()); } - if (actionPerformed) { + if (requiresReanalysis) { reprocess(dossierId, fileId); } analysisFlagsCalculationService.calculateFlags(dossierId, fileId); } - private ManualImageRecategorizationEntity getImageRecategorization(String fileId, String annotationId) { + private ManualImageRecategorizationEntity getRecategorization(String fileId, String annotationId) { return recategorizationPersistenceService.findRecategorization(fileId, annotationId); } @Transactional - public void deleteComment(String fileId, List commentIds) { + public void deleteComment(String dossierId, String fileId, List commentIds) { for (var commentId : commentIds) { commentPersistenceService.softDelete(commentId, OffsetDateTime.now()); } // update indicator fileStatusPersistenceService.updateHasComments(fileId, commentPersistenceService.fileHasComments(fileId)); + // if file is currently not analyzing, we can quickly change the redaction log, else we must wait for the analysis to finish. + if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { + reprocess(dossierId, fileId); + return; + } + fileStatusService.setStatusProcessing(fileId); + RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + redactionLog.getRedactionLogEntry().forEach(entry -> entry.getComments().removeIf(comment -> commentIds.contains(comment.getId()))); + fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); + fileStatusService.setStatusProcessed(fileId); } @@ -573,14 +592,14 @@ public class ManualRedactionService { List response = new ArrayList<>(); - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId, true, true); + RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); for (ResizeRedactionRequest resizeRedactionRequest : resizeRedactionRequests) { var resizeRedaction = resizeRedactionPersistenceService.insert(fileId, resizeRedactionRequest); if (resizeRedactionRequest.getComment() != null) { - Long commentId = addComment(fileId, resizeRedactionRequest.getAnnotationId(), resizeRedactionRequest.getComment(), resizeRedactionRequest.getUser()).getId(); + Long commentId = addCommentAndGetId(fileId, resizeRedactionRequest.getAnnotationId(), resizeRedactionRequest.getComment(), resizeRedactionRequest.getUser()); response.add(ManualAddResponse.builder().annotationId(resizeRedactionRequest.getAnnotationId()).commentId(commentId).build()); } @@ -675,7 +694,7 @@ public class ManualRedactionService { @Transactional - public void updateProcessedDate(String fileId, ManualRedactions manualRedactions) { + public void updateProcessedDate(ManualRedactions manualRedactions) { if (manualRedactions != null) { @@ -717,4 +736,13 @@ public class ManualRedactionService { } } + + public Comments getComments(String fileId) { + + return new Comments(commentPersistenceService.findCommentsByFileID(fileId, false) + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> MagicConverter.convert(entry.getValue(), Comment.class)))); + } + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java new file mode 100644 index 000000000..6eac5cba6 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java @@ -0,0 +1,247 @@ +package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions; + +import static com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource.ANNOTATION_ID; +import static com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource.DOSSIER_ID; +import static com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource.FILE_ID; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Service; + +import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; +import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualImageRecategorization; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange; +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.annotations.entitymapped.ManualResizeRedaction; +import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ManualRedactionWrapperModel; +import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class ManualRedactionUndoService { + + private final ManualRedactionService manualRedactionService; + private final AuditPersistenceService auditPersistenceService; + private final FileStatusService fileStatusService; + + + public void undo(String dossierId, String fileId, Set annotationIds) { + + // undo the latest manual redaction for each annotationId + ManualRedactions manualRedactions = manualRedactionService.getManualRedactions(fileId); + + Map manualRedactionWrappers = getLatestManualRedactionsForAnnotationIds(manualRedactions, annotationIds); + + if (manualRedactionWrappers.isEmpty()) { + throw new NotFoundException(String.format("ManualRedaction with annotationIds %s could not be found.", annotationIds)); + } + + undoManualRedactionEntries(dossierId, fileId, manualRedactionWrappers); + undoIdRemovals(dossierId, fileId, manualRedactionWrappers); + undoForceRedactions(dossierId, fileId, manualRedactionWrappers); + undoRecategorization(dossierId, fileId, manualRedactionWrappers); + undoLegalBasisChange(dossierId, fileId, manualRedactionWrappers); + undoResize(dossierId, fileId, manualRedactionWrappers); + reprocess(dossierId, fileId); + } + + private void reprocess(String dossierId, String fileId) { + + fileStatusService.setStatusReprocessForManual(dossierId, fileId, true); + } + + + private void undoResize(String dossierId, String fileId, Map manualRedactionWrappers) { + + List manualResizeRedactions = manualRedactionWrappers.values() + .stream() + .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualResizeRedaction) + .map(ManualRedactionWrapperModel::getId) + .collect(Collectors.toList()); + if (!manualResizeRedactions.isEmpty()) { + manualRedactionService.deleteResizeRedaction(dossierId, fileId, manualResizeRedactions); + manualResizeRedactions.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(fileId) + .category(AuditCategory.DOCUMENT.name()) + .message("Undo of manual resize redaction was done.") + .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) + .build())); + } + } + + + private void undoLegalBasisChange(String dossierId, String fileId, Map manualRedactionWrappers) { + + List manualLegalBasisChanges = manualRedactionWrappers.values() + .stream() + .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualLegalBasisChange) + .map(ManualRedactionWrapperModel::getId) + .collect(Collectors.toList()); + if (!manualLegalBasisChanges.isEmpty()) { + + manualRedactionService.deleteLegalBasisChange(dossierId, fileId, manualLegalBasisChanges); + manualLegalBasisChanges.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(fileId) + .category(AuditCategory.DOCUMENT.name()) + .message("Undo of legal basis change was done.") + .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) + .build())); + } + } + + + private void undoRecategorization(String dossierId, String fileId, Map manualRedactionWrappers) { + + List manualImageRecategorizations = manualRedactionWrappers.values() + .stream() + .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualImageRecategorization) + .map(ManualRedactionWrapperModel::getId) + .collect(Collectors.toList()); + if (!manualImageRecategorizations.isEmpty()) { + + manualRedactionService.deleteRecategorization(dossierId, fileId, manualImageRecategorizations); + manualImageRecategorizations.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(fileId) + .category(AuditCategory.DOCUMENT.name()) + .message("Undo of manual image recategorization was done.") + .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) + .build())); + } + } + + + private void undoForceRedactions(String dossierId, String fileId, Map manualRedactionWrappers) { + + List manualForceRedactions = manualRedactionWrappers.values() + .stream() + .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualForceRedaction) + .map(ManualRedactionWrapperModel::getId) + .collect(Collectors.toList()); + if (!manualForceRedactions.isEmpty()) { + + manualRedactionService.deleteForceRedaction(dossierId, fileId, manualForceRedactions); + manualForceRedactions.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(fileId) + .category(AuditCategory.DOCUMENT.name()) + .message("Undo of manual force redaction was done.") + .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) + .build())); + } + } + + + private void undoIdRemovals(String dossierId, String fileId, Map manualRedactionWrappers) { + + List idRemovals = manualRedactionWrappers.values() + .stream() + .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof IdRemoval) + .map(ManualRedactionWrapperModel::getId) + .collect(Collectors.toList()); + if (!idRemovals.isEmpty()) { + manualRedactionService.deleteRemoveRedaction(dossierId, fileId, idRemovals); + idRemovals.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(fileId) + .category(AuditCategory.DOCUMENT.name()) + .message("Undo of manual remove redaction was done.") + .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) + .build())); + } + } + + + private void undoManualRedactionEntries(String dossierId, String fileId, Map manualRedactionWrappers) { + + List manualRedactionEntries = manualRedactionWrappers.values() + .stream() + .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualRedactionEntry) + .map(ManualRedactionWrapperModel::getId) + .collect(Collectors.toList()); + if (!manualRedactionEntries.isEmpty()) { + manualRedactionService.deleteAddRedaction(dossierId, fileId, manualRedactionEntries); + manualRedactionEntries.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(fileId) + .category(AuditCategory.DOCUMENT.name()) + .message("Undo of manual add redaction was done.") + .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) + .build())); + } + } + + + private Map getLatestManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set annotationIds) { + + Map result = new HashMap<>(); + annotationIds.forEach(annotationId -> { + var last = getLatestManualRedactionForAnnotationId(manualRedactions, annotationId); + if (last != null) { + result.put(annotationId, last); + } + }); + + return result; + } + + + private ManualRedactionWrapperModel getLatestManualRedactionForAnnotationId(ManualRedactions manualRedactions, String annotationId) { + + final List manualRedactionWrappers = new ArrayList<>(); + + manualRedactions.getEntriesToAdd() + .stream() + .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); + + manualRedactions.getImageRecategorization() + .stream() + .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); + + manualRedactions.getIdsToRemove() + .stream() + .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); + + manualRedactions.getForceRedactions() + .stream() + .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); + + manualRedactions.getLegalBasisChanges() + .stream() + .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); + + manualRedactions.getResizeRedactions() + .stream() + .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) + .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item))); + + var sortedManualRedactionWrappers = manualRedactionWrappers.stream() + .sorted(Comparator.comparing(ManualRedactionWrapperModel::getDate, Comparator.nullsLast(Comparator.reverseOrder()))) + .toList(); + + return sortedManualRedactionWrappers.isEmpty() ? null : sortedManualRedactionWrappers.get(0); + } + +} 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/Comments.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comments.java new file mode 100644 index 000000000..07bce8c08 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comments.java @@ -0,0 +1,19 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations; + +import java.util.List; +import java.util.Map; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class Comments { + + Map> comments; + +} -- 2.47.2 From aab2971d6e03431d7deaae6f244a81bed11cdf4b Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Tue, 29 Aug 2023 18:07:42 +0200 Subject: [PATCH 3/7] RED-7317: Endpoint to change entity types of dict-based annotations * major refactor of manual redaction service --- .../controller/ManualRedactionController.java | 16 +- .../controller/RedactionLogController.java | 2 +- .../RedactionLogInternalController.java | 2 +- .../ManualImageRecategorizationEntity.java | 28 +- .../AnalysisFlagsCalculationService.java | 2 +- .../service/FileManagementStorageService.java | 14 +- .../FileStatusProcessingUpdateService.java | 5 +- .../service/RedactionLogService.java | 59 +- ...anualRedactionDictionaryUpdateHandler.java | 109 +++- .../ManualRedactionService.java | 118 ++-- .../AddRedactionPersistenceService.java | 2 +- ...ageRecategorizationPersistenceService.java | 20 + .../RedactionLogMergeService.java | 549 ------------------ .../db/changelog/db.changelog-tenant.yaml | 2 + ...ry-changes-to-manual-recategorization.yaml | 79 +++ .../tests/ManualRedactionTest.java | 32 +- .../integration/tests/RedactionLogTest.java | 47 -- .../AbstractPersistenceServerServiceTest.java | 6 +- .../annotations/AddRedactionRequest.java | 2 +- ... => ManualRequestWithAddToDictionary.java} | 3 +- ...ManualRequestWithRemoveFromDictionary.java | 13 + .../annotations/RecategorizationRequest.java | 16 +- .../annotations/RemoveRedactionRequest.java | 2 +- 23 files changed, 357 insertions(+), 771 deletions(-) delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/RedactionLogMergeService.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/108-added-dictionary-changes-to-manual-recategorization.yaml delete mode 100644 persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/RedactionLogTest.java rename persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/{ManualRequestWithDictionary.java => ManualRequestWithAddToDictionary.java} (79%) create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithRemoveFromDictionary.java 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 4ce41002b..548846f37 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 @@ -32,7 +32,9 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RecategorizationRequest; 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.type.DictionaryEntryType; 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; @@ -88,7 +90,7 @@ public class ManualRedactionController implements ManualRedactionResource { .message("Comment was removed.") .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) .build()); - manualRedactionService.deleteComment(fileId, List.of(Long.valueOf(commentId))); + manualRedactionService.deleteComment(dossierId, fileId, List.of(Long.valueOf(commentId))); } @@ -100,6 +102,7 @@ public class ManualRedactionController implements ManualRedactionResource { return manualRedactionService.getManualRedactions(fileId); } + @Override @PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')") public Comments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { @@ -118,7 +121,8 @@ public class ManualRedactionController implements ManualRedactionResource { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId); - var response = manualRedactionService.addComment(fileId, + var response = manualRedactionService.addComment(dossierId, + fileId, annotationId, CommentRequest.builder().user(KeycloakSecurity.getUserId()).text(addCommentRequest.getText()).build()); @@ -298,15 +302,17 @@ public class ManualRedactionController implements ManualRedactionResource { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsMemberOrApprover(dossierId); - List requests = recategorizationRequests.stream() - .map(recategorizationRequest -> com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RecategorizationRequest.builder() + List requests = recategorizationRequests.stream() + .map(recategorizationRequest -> RecategorizationRequest.builder() .annotationId(recategorizationRequest.getAnnotationId()) .user(KeycloakSecurity.getUserId()) .status(AnnotationStatus.APPROVED) - .typeId(toTypeId(recategorizationRequest.getType(), dossier.getDossierTemplateId())) + .dossierTemplateTypeId(toTypeId(recategorizationRequest.getType(), dossier.getDossierTemplateId())) .comment(recategorizationRequest.getComment()) + .dossierId(dossierId) .addToDictionary(recategorizationRequest.isAddToDictionary()) .addToAllDossiers(recategorizationRequest.isAddToAllDossiers()) + .dictionaryEntryType(DictionaryEntryType.ENTRY) .build()) .collect(Collectors.toList()); 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/RedactionLogController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/RedactionLogController.java index e38a34b89..a9aa72d55 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/RedactionLogController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/RedactionLogController.java @@ -52,7 +52,7 @@ public class RedactionLogController implements RedactionLogResource { @RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives) { try { - return redactionLogService.getRedactionLog(dossierId, fileId, excludedTypes, withManualRedactions, includeFalsePositives); + return redactionLogService.getRedactionLog(dossierId, fileId, excludedTypes); } catch (FeignException e) { throw processFeignException(e); } diff --git a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/RedactionLogInternalController.java b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/RedactionLogInternalController.java index 878daa64a..f9c1a9f33 100644 --- a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/RedactionLogInternalController.java +++ b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/RedactionLogInternalController.java @@ -25,7 +25,7 @@ public class RedactionLogInternalController implements RedactionLogResource { @RequestParam(value = "withManualRedactions", required = false, defaultValue = "true") boolean withManualRedactions, @RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives) { - return redactionLogService.getRedactionLog(dossierId, fileId, excludedTypes, withManualRedactions, includeFalsePositives); + return redactionLogService.getRedactionLog(dossierId, fileId, excludedTypes); } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/annotations/ManualImageRecategorizationEntity.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/annotations/ManualImageRecategorizationEntity.java index 0bc4031a3..a4900d2a6 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/annotations/ManualImageRecategorizationEntity.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/annotations/ManualImageRecategorizationEntity.java @@ -1,18 +1,24 @@ package com.iqser.red.service.persistence.management.v1.processor.entity.annotations; import java.time.OffsetDateTime; +import java.util.HashSet; +import java.util.Set; +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.FetchMode; + +import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; + +import jakarta.persistence.CollectionTable; import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; import jakarta.persistence.EmbeddedId; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; - -import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; - import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -43,8 +49,22 @@ public class ManualImageRecategorizationEntity implements IBaseAnnotation { private OffsetDateTime softDeletedTime; @Column private int page; + @Column + private boolean addToDictionary; + @Column + private boolean addToAllDossiers; @ManyToOne private FileEntity fileStatus; + @ElementCollection + @CollectionTable(name = "manual_recategorization_type_ids_of_dictionaries_with_add") + @Fetch(value = FetchMode.SUBSELECT) + private Set typeIdsOfDictionariesWithAdd = new HashSet<>(); + + @ElementCollection + @CollectionTable(name = "manual_recategorization_type_ids_of_dictionaries_with_delete") + @Fetch(value = FetchMode.SUBSELECT) + private Set typeIdsOfDictionariesWithDelete = new HashSet<>(); + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/AnalysisFlagsCalculationService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/AnalysisFlagsCalculationService.java index ee750cc7e..e5f484bf1 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/AnalysisFlagsCalculationService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/AnalysisFlagsCalculationService.java @@ -36,7 +36,7 @@ public class AnalysisFlagsCalculationService { long startTime = System.currentTimeMillis(); var file = fileStatusPersistenceService.getStatus(fileId); - var redactionLog = redactionLogService.getRedactionLog(dossierId, fileId, true, false); + var redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); var viewedPagesForCurrentAssignee = viewedPagesPersistenceService.findViewedPages(fileId, file.getAssignee()); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java index 34b234218..27bcc7e41 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java @@ -9,12 +9,14 @@ import java.nio.file.StandardOpenOption; import org.apache.commons.io.IOUtils; import org.springframework.stereotype.Service; +import com.iqser.red.service.persistence.management.v1.processor.exception.InternalServerErrorException; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.utils.StorageIdUtils; 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.redactionlog.RedactionLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.imported.ImportedRedactions; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid; +import com.iqser.red.storage.commons.exception.StorageException; import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist; import com.iqser.red.storage.commons.service.StorageService; import com.knecon.fforesight.tenantcommons.TenantContext; @@ -50,6 +52,7 @@ public class FileManagementStorageService { return storedObjectBytes; } + @SneakyThrows public InputStream getObject(String tenantId, String storageId) { @@ -83,11 +86,20 @@ public class FileManagementStorageService { return storageService.readJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.REDACTION_LOG), RedactionLog.class); } catch (StorageObjectDoesNotExist e) { log.debug("RedactionLog does not exist"); - throw new NotFoundException("RedactionLog does not exist"); + throw new NotFoundException(String.format("RedactionLog does not exist for Dossier ID \"%s\" and File ID \"%s\"!", dossierId, fileId)); + } catch (StorageException e) { + throw new InternalServerErrorException(e.getMessage()); } } + public void storeRedactionLog(String dossierId, String fileId, RedactionLog redactionLog) { + + storageService.storeJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.REDACTION_LOG), redactionLog); + + } + + public SectionGrid getSectionGrid(String dossierId, String fileId) { try { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusProcessingUpdateService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusProcessingUpdateService.java index 0693c05ad..258e3de36 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusProcessingUpdateService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusProcessingUpdateService.java @@ -1,7 +1,5 @@ package com.iqser.red.service.persistence.management.v1.processor.service; -import jakarta.transaction.Transactional; - import org.apache.commons.lang3.StringUtils; import org.springframework.retry.support.RetryTemplate; import org.springframework.web.bind.annotation.RestController; @@ -17,6 +15,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus; import com.iqser.red.service.search.v1.model.IndexMessageType; +import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -54,7 +53,7 @@ public class FileStatusProcessingUpdateService { indexingService.addToIndexingQueue(IndexMessageType.INSERT, dossier.getDossierTemplateId(), dossierId, fileId, 2); } - manualRedactionService.updateProcessedDate(fileId, analyzeResult.getManualRedactions()); + manualRedactionService.updateProcessedDate(analyzeResult.getManualRedactions()); analysisFlagsCalculationService.calculateFlags(dossierId, fileId); if (analyzeResult.getAddedFileAttributes() != null && !analyzeResult.getAddedFileAttributes().isEmpty()) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/RedactionLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/RedactionLogService.java index 252560442..cc6923749 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/RedactionLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/RedactionLogService.java @@ -2,26 +2,17 @@ package com.iqser.red.service.persistence.management.v1.processor.service; import java.time.OffsetDateTime; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; -import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; -import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.redactionlog.RedactionLogMergeService; -import com.iqser.red.service.persistence.management.v1.processor.service.redactionlog.RedactionRequest; -import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.Type; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.FilteredRedactionLogRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid; -import feign.FeignException; import lombok.RequiredArgsConstructor; @Service @@ -29,59 +20,29 @@ import lombok.RequiredArgsConstructor; public class RedactionLogService { private final FileManagementStorageService fileManagementStorageService; - private final ManualRedactionProviderService manualRedactionService; - private final DossierPersistenceService dossierPersistenceService; private final FileStatusService fileStatusService; - private final ColorsService colorsService; - private final DictionaryPersistenceService dictionaryPersistenceService; - private final RedactionLogMergeService redactionLogMergeService; - public RedactionLog getRedactionLog(String dossierId, String fileId, boolean withManualRedactions, boolean includeFalsePositives) { + public RedactionLog getRedactionLog(String dossierId, String fileId) { - return getRedactionLog(dossierId, fileId, null, withManualRedactions, includeFalsePositives); + return getRedactionLog(dossierId, fileId, Collections.emptyList()); } - public RedactionLog getRedactionLog(String dossierId, String fileId, List excludedTypes, boolean withManualRedactions, boolean includeFalsePositives) { + public RedactionLog getRedactionLog(String dossierId, String fileId, List excludedTypes) { var fileStatus = fileStatusService.getStatus(fileId); RedactionLog redactionLog; - if (withManualRedactions) { - var dossier = dossierPersistenceService.findByDossierId(dossierId); - var manualRedactions = manualRedactionService.getManualRedactions(fileId); - var colors = MagicConverter.convert(colorsService.getColors(dossier.getDossierTemplateId()), Colors.class); - var types = MagicConverter.convert(dictionaryPersistenceService.getAllTypesForDossierTemplate(dossier.getDossierTemplateId(), true), Type.class); - var dossierTypes = MagicConverter.convert(dictionaryPersistenceService.getAllTypesForDossier(dossierId, true), Type.class); - types.addAll(dossierTypes); - - try { - redactionLog = redactionLogMergeService.provideRedactionLog(RedactionRequest.builder() - .dossierId(dossierId) - .fileId(fileId) - .manualRedactions(manualRedactions) - .dossierTemplateId(dossier.getDossierTemplateId()) - .excludedPages(fileStatus.getExcludedPages()) - .includeFalsePositives(includeFalsePositives) - .colors(colors) - .types(types) - .build()); - } catch (FeignException e) { - if (e.status() == HttpStatus.NOT_FOUND.value()) { - throw new NotFoundException(e.getMessage()); - } - throw e; - } - } else { - redactionLog = fileManagementStorageService.getRedactionLog(dossierId, fileId); - } + redactionLog = fileManagementStorageService.getRedactionLog(dossierId, fileId); if (fileStatus.isExcluded()) { redactionLog.setRedactionLogEntry(new ArrayList<>()); } + if (fileStatus.isHasUpdates()) + if (excludedTypes != null) { redactionLog.getRedactionLogEntry().removeIf(nextEntry -> excludedTypes.contains(nextEntry.getType())); } @@ -102,11 +63,7 @@ public class RedactionLogService { filteredRedactionLogRequest.setSpecifiedDate(OffsetDateTime.MIN); } - var redactionLog = getRedactionLog(dossierId, - fileId, - filteredRedactionLogRequest.getExcludedTypes(), - filteredRedactionLogRequest.isWithManualRedactions(), - filteredRedactionLogRequest.isIncludeFalsePositives()); + var redactionLog = getRedactionLog(dossierId, fileId, filteredRedactionLogRequest.getExcludedTypes()); var redactionLogEntries = redactionLog.getRedactionLogEntry(); Iterator it = redactionLogEntries.iterator(); 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 71109936c..14d26e786 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 @@ -1,19 +1,26 @@ package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions; -import java.util.Collections; +import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId; + import java.util.HashSet; import java.util.List; import java.util.Set; import org.springframework.stereotype.Service; -import com.iqser.red.service.dictionarymerge.commons.DictionaryEntry; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithDictionary; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithAddToDictionary; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithRemoveFromDictionary; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; 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.redactionlog.RedactionLogEntry; import feign.FeignException; import lombok.RequiredArgsConstructor; @@ -25,33 +32,46 @@ import lombok.extern.slf4j.Slf4j; public class ManualRedactionDictionaryUpdateHandler { private final DictionaryManagementService dictionaryManagementService; + private final AddRedactionPersistenceService addRedactionPersistenceService; + private final FileStatusPersistenceService fileStatusPersistenceService; + private final ResizeRedactionPersistenceService resizeRedactionPersistenceService; + private final DossierPersistenceService dossierPersistenceService; - public Set handleAddToDictionary(String fileId, String dossierId, ManualRequestWithDictionary manualRequestWithDictionary) { + public Set handleAddToDictionaryAndReturnModifiedTypeIds(String fileId, String annotationId, ManualRequestWithAddToDictionary manualRequestWithAddToDictionary) { - if (!manualRequestWithDictionary.isApproved()) { - return Collections.emptySet(); + if (!manualRequestWithAddToDictionary.isApproved()) { + return null; + } + + if (!manualRequestWithAddToDictionary.isAddToDictionary()) { + addRedactionPersistenceService.updateStatus(fileId, annotationId, manualRequestWithAddToDictionary.getStatus(), false, null); + return null; } Set typeIdsOfModifiedDictionaries = new HashSet<>(); - - String dossierTemplateTypeId = manualRequestWithDictionary.getDossierTemplateTypeId(); - String value = manualRequestWithDictionary.getValue(); - DictionaryEntryType dictionaryEntryType = manualRequestWithDictionary.getDictionaryEntryType(); - - if (manualRequestWithDictionary.isAddToAllDossiers()) { - List dictionaryEntriesToUnDelete = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplateTypeId, value); + if (manualRequestWithAddToDictionary.isAddToAllDossiers()) { + var dictionaryEntriesToUnDelete = dictionaryManagementService.getAllEntriesInDossierTemplate(manualRequestWithAddToDictionary.getDossierTemplateTypeId(), + manualRequestWithAddToDictionary.getValue()); dictionaryEntriesToUnDelete.forEach(entry -> { typeIdsOfModifiedDictionaries.add(entry.getTypeId()); - addToDictionary(entry.getTypeId(), manualRequestWithDictionary.getValue(), dossierId, fileId, manualRequestWithDictionary.getDictionaryEntryType()); + addToDictionary(entry.getTypeId(), manualRequestWithAddToDictionary.getValue(), manualRequestWithAddToDictionary.getDossierId(), fileId, manualRequestWithAddToDictionary.getDictionaryEntryType()); }); - addToDictionary(dossierTemplateTypeId, value, dossierId, fileId, dictionaryEntryType); - typeIdsOfModifiedDictionaries.add(dossierTemplateTypeId); - } else { - addToDictionary(dossierTemplateTypeId + ":" + dossierId, value, dossierId, fileId, dictionaryEntryType); - typeIdsOfModifiedDictionaries.add(dossierTemplateTypeId + ":" + dossierId); + addToDictionary(manualRequestWithAddToDictionary.getDossierTemplateTypeId(), + manualRequestWithAddToDictionary.getValue(), + manualRequestWithAddToDictionary.getDossierId(), + fileId, + manualRequestWithAddToDictionary.getDictionaryEntryType()); + typeIdsOfModifiedDictionaries.add(manualRequestWithAddToDictionary.getDossierTemplateTypeId()); + return typeIdsOfModifiedDictionaries; } - + addToDictionary(manualRequestWithAddToDictionary.getDossierTemplateTypeId() + ":" + manualRequestWithAddToDictionary.getDossierId(), + manualRequestWithAddToDictionary.getValue(), + manualRequestWithAddToDictionary.getDossierId(), + fileId, + manualRequestWithAddToDictionary.getDictionaryEntryType()); + typeIdsOfModifiedDictionaries.add(manualRequestWithAddToDictionary.getDossierTemplateTypeId() + ":" + manualRequestWithAddToDictionary.getDossierId()); return typeIdsOfModifiedDictionaries; + } @@ -89,4 +109,53 @@ public class ManualRedactionDictionaryUpdateHandler { } } + + public Set handleRemoveFromDictionaryAndReturnModifiedTypeIds(RedactionLogEntry redactionLogEntry, + String fileId, + String dossierId, + String dossierTemplateId, + ManualRequestWithRemoveFromDictionary manualRequestWithRemoveFromDictionary) { + + if (!manualRequestWithRemoveFromDictionary.isApproved()) { + return null; + } + + if (!manualRequestWithRemoveFromDictionary.isRemoveFromDictionary()) { + + return null; + } + + Set typeIdsOfModifiedDictionaries = new HashSet<>(); + if (manualRequestWithRemoveFromDictionary.isRemoveFromAllDossiers()) { + var dictionaryEntriesToRemove = dictionaryManagementService.getAllEntriesInDossierTemplate(toTypeId(redactionLogEntry.getType(), dossierTemplateId), + redactionLogEntry.getValue()); + dictionaryEntriesToRemove.forEach(entry -> { + typeIdsOfModifiedDictionaries.add(entry.getTypeId()); + removeFromDictionary(entry.getTypeId(), entry.getValue(), dossierId, fileId, DictionaryEntryType.ENTRY); + }); + } else { + typeIdsOfModifiedDictionaries.add(toTypeId(redactionLogEntry.getType(), dossierTemplateId, dossierId)); + removeFromDictionary(toTypeId(redactionLogEntry.getType(), dossierTemplateId, dossierId), redactionLogEntry.getValue(), dossierId, fileId, DictionaryEntryType.ENTRY); + } + + // This is needed to remove resizeRedactions with addToDictionary. + removeResizeRedactionsWithAddToDictionary(dossierTemplateId, redactionLogEntry.getValue()); + + return typeIdsOfModifiedDictionaries; + } + + + private void removeResizeRedactionsWithAddToDictionary(String dossierTemplateId, String redactionLogEntryValue) { + + var resizeRedactionsWithSameValue = resizeRedactionPersistenceService.findByAnnotationStatusAndValue(AnnotationStatus.APPROVED, redactionLogEntryValue); + resizeRedactionsWithSameValue.forEach(resizeRedaction -> { + var file = fileStatusPersistenceService.getStatus(resizeRedaction.getId().getFileId()); + var dossierForResizeRedaction = dossierPersistenceService.findByDossierId(file.getDossierId()); + if (!file.getWorkflowStatus().equals(WorkflowStatus.APPROVED) && dossierTemplateId.equals(dossierForResizeRedaction.getDossierTemplateId())) { + resizeRedactionPersistenceService.hardDelete(resizeRedaction.getId().getFileId(), resizeRedaction.getId().getAnnotationId()); + } + }); + } + + } 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 5310ed49c..c5f64a39d 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 @@ -54,15 +54,15 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations 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.ManualAddResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithDictionary; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithAddToDictionary; 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.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.IdRemoval; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; 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.redactionlog.RedactionLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogComment; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; @@ -110,7 +110,16 @@ public class ManualRedactionService { String annotationId = hashFunction.hashString(fileId + addRedactionRequest, StandardCharsets.UTF_8).toString(); addRedactionPersistenceService.insert(fileId, annotationId, addRedactionRequest); - manualRedactionDictionaryUpdateHandler.handleAddToDictionary(fileId, annotationId, addRedactionRequest); + + Set typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.handleAddToDictionaryAndReturnModifiedTypeIds(fileId, + annotationId, + addRedactionRequest); + + addRedactionPersistenceService.updateStatus(fileId, + annotationId, + addRedactionRequest.getStatus(), + typeIdsOfModifiedDictionaries != null, + typeIdsOfModifiedDictionaries); Long commentId = addCommentAndGetId(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser()); @@ -127,7 +136,7 @@ public class ManualRedactionService { } - private void validateDictionaries(ManualRequestWithDictionary addRedactionRequest) { + private void validateDictionaries(ManualRequestWithAddToDictionary addRedactionRequest) { if (addRedactionRequest.isAddToDictionary()) { if (addRedactionRequest.isAddToAllDossiers()) { @@ -139,7 +148,7 @@ public class ManualRedactionService { } - private void validateDictionary(ManualRequestWithDictionary addRedactionRequest) { + private void validateDictionary(ManualRequestWithAddToDictionary addRedactionRequest) { try { if (!addRedactionRequest.isForceAddToDictionary() && stopwordService.isStopword(addRedactionRequest.getValue())) { @@ -263,11 +272,20 @@ public class ManualRedactionService { requiresReAnalysis = requiresReAnalysis || matchingEntryFound; } - boolean removedFromDictionary = handleRemoveFromDictionary(getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId()), - dossier, - fileId, + Set typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.handleRemoveFromDictionaryAndReturnModifiedTypeIds(// + getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId()),// + dossierId, // + dossier.getDossierTemplateId(),// + fileId, // removeRedactionRequest); + boolean removedFromDictionary = typeIdsOfModifiedDictionaries != null; + removeRedactionPersistenceService.updateStatus(fileId, + removeRedactionRequest.getAnnotationId(), + removeRedactionRequest.getStatus(), + removedFromDictionary, + typeIdsOfModifiedDictionaries); + if (!matchingEntryFound && !removedFromDictionary && idRemoval.isApproved()) { removeRedactionPersistenceService.markAsProcessed(idRemoval); } @@ -311,40 +329,7 @@ public class ManualRedactionService { } - private boolean handleRemoveFromDictionary(RedactionLogEntry redactionLogEntry, DossierEntity dossier, String fileId, RemoveRedactionRequest removeRedactionRequest) { - if (!removeRedactionRequest.isApproved()) { - return false; - } - - if (!removeRedactionRequest.isRemoveFromDictionary()) { - removeRedactionPersistenceService.updateStatus(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getStatus(), false, Collections.emptySet()); - return false; - } - - Set typeIdsOfModifiedDictionaries = new HashSet<>(); - if (removeRedactionRequest.isRemoveFromAllDossiers()) { - var dictionaryEntriesToRemove = dictionaryManagementService.getAllEntriesInDossierTemplate(toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId()), - redactionLogEntry.getValue()); - dictionaryEntriesToRemove.forEach(entry -> { - typeIdsOfModifiedDictionaries.add(entry.getTypeId()); - removeFromDictionary(entry.getTypeId(), entry.getValue(), dossier.getId(), fileId, DictionaryEntryType.ENTRY); - }); - } else { - typeIdsOfModifiedDictionaries.add(toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId())); - removeFromDictionary(toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId()), - redactionLogEntry.getValue(), - dossier.getId(), - fileId, - DictionaryEntryType.ENTRY); - } - - // This is needed to remove resizeRedactions with addToDictionary. - removeResizeRedactionsWithAddToDictionary(dossier.getDossierTemplateId(), redactionLogEntry.getValue()); - - removeRedactionPersistenceService.updateStatus(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getStatus(), true, typeIdsOfModifiedDictionaries); - return true; - } private RedactionLogEntry getRedactionLogEntry(RedactionLog redactionLog, String annotationId) { @@ -357,18 +342,6 @@ public class ManualRedactionService { } - private void removeResizeRedactionsWithAddToDictionary(String dossierTemplateId, String redactionLogEntryValue) { - - var resizeRedactionsWithSameValue = resizeRedactionPersistenceService.findByAnnotationStatusAndValue(AnnotationStatus.APPROVED, redactionLogEntryValue); - resizeRedactionsWithSameValue.forEach(resizeRedaction -> { - var file = fileStatusPersistenceService.getStatus(resizeRedaction.getId().getFileId()); - var dossierForResizeRedaction = dossierPersistenceService.findByDossierId(file.getDossierId()); - if (!file.getWorkflowStatus().equals(WorkflowStatus.APPROVED) && dossierTemplateId.equals(dossierForResizeRedaction.getDossierTemplateId())) { - resizeRedactionPersistenceService.hardDelete(resizeRedaction.getId().getFileId(), resizeRedaction.getId().getAnnotationId()); - } - }); - } - @Transactional public List addForceRedaction(String dossierId, String fileId, List forceRedactionRequests) { @@ -420,11 +393,31 @@ public class ManualRedactionService { var response = new ArrayList(); var requiresReanalysis = false; - dossierPersistenceService.getAndValidateDossier(dossierId); - + var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); + RedactionLog redactionLog = fileManagementStorageService.getRedactionLog(dossierId, fileId); for (var recategorizationRequest : recategorizationRequests) { + validateDictionaries(recategorizationRequest); + recategorizationPersistenceService.insert(fileId, recategorizationRequest); + Set typeIdsOfDictionariesWithAdd = manualRedactionDictionaryUpdateHandler.handleAddToDictionaryAndReturnModifiedTypeIds(fileId, + recategorizationRequest.getAnnotationId(), + recategorizationRequest); + + Set typeIdsOfDictionariesWithDelete = manualRedactionDictionaryUpdateHandler.handleRemoveFromDictionaryAndReturnModifiedTypeIds(// + getRedactionLogEntry(redactionLog, recategorizationRequest.getAnnotationId()),// + recategorizationRequest.getDossierId(),// + dossier.getDossierTemplateId(),// + fileId,// + recategorizationRequest); + + recategorizationPersistenceService.updateStatus(fileId, + recategorizationRequest.getAnnotationId(), + AnnotationStatus.APPROVED, + typeIdsOfDictionariesWithAdd != null, + typeIdsOfDictionariesWithAdd, + typeIdsOfDictionariesWithDelete); + Long commentId = addCommentAndGetId(fileId, recategorizationRequest.getAnnotationId(), recategorizationRequest.getComment(), recategorizationRequest.getUser()); requiresReanalysis = requiresReanalysis || recategorizationRequest.getStatus().equals(AnnotationStatus.APPROVED); @@ -441,12 +434,23 @@ public class ManualRedactionService { } - public CommentEntity addComment(String fileId, String annotationId, CommentRequest commentRequest) { + public CommentEntity addComment(String dossierId, String fileId, String annotationId, CommentRequest commentRequest) { CommentEntity createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser()); fileStatusPersistenceService.updateHasComments(fileId, true); - + if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { + reprocess(dossierId, fileId); + return createdComment; + } + fileStatusService.setStatusProcessing(fileId); + RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + redactionLog.getRedactionLogEntry() + .stream() + .filter(entry -> entry.getId().equals(annotationId)) + .forEach(entry -> entry.getComments().add(MagicConverter.convert(createdComment, RedactionLogComment.class))); + fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); + fileStatusService.setStatusProcessed(fileId); return createdComment; } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java index 20b98dd31..050056a39 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java @@ -119,7 +119,7 @@ public class AddRedactionPersistenceService { boolean isAddOrRemoveFromDictionary, Set typeIdsOfModifiedDictionaries) { - var addRedaction = manualRedactionRepository.findById(new AnnotationEntityId(annotationId, fileId)) + ManualRedactionEntryEntity addRedaction = manualRedactionRepository.findById(new AnnotationEntityId(annotationId, fileId)) .orElseThrow(() -> new NotFoundException("Unknown file/annotation combination: " + fileId + "/" + annotationId)); addRedaction.setStatus(annotationStatus); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java index 632b6d3cf..a2151494c 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java @@ -3,6 +3,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service.persis import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.List; +import java.util.Set; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; @@ -43,6 +44,25 @@ public class ImageRecategorizationPersistenceService { imageRecategorizationRepository.updateStatus(new AnnotationEntityId(annotationId, fileId), annotationStatus); } + @Transactional + public void updateStatus(String fileId, + String annotationId, + AnnotationStatus annotationStatus, + boolean modifiedDictionary, + Set typeIdsOfDictionaryWithAdd, + Set typeIdsOfDictionaryWithDelete) { + + ManualImageRecategorizationEntity addRedaction = imageRecategorizationRepository.findById(new AnnotationEntityId(annotationId, fileId)) + .orElseThrow(() -> new NotFoundException("Unknown file/annotation combination: " + fileId + "/" + annotationId)); + + addRedaction.setStatus(annotationStatus); + addRedaction.setAddToDictionary(modifiedDictionary); + addRedaction.setTypeIdsOfDictionariesWithAdd(typeIdsOfDictionaryWithAdd); + addRedaction.setTypeIdsOfDictionariesWithDelete(typeIdsOfDictionaryWithDelete); + + imageRecategorizationRepository.saveAndFlush(addRedaction); + } + @Transactional public void hardDelete(String fileId, String annotationId) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/RedactionLogMergeService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/RedactionLogMergeService.java deleted file mode 100644 index 31f11bce4..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/RedactionLogMergeService.java +++ /dev/null @@ -1,549 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.service.redactionlog; - -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import org.springframework.stereotype.Service; - -import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; -import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; -import com.iqser.red.service.persistence.management.v1.processor.utils.ColorUtils; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualImageRecategorization; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange; -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.annotations.entitymapped.ManualResizeRedaction; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.Type; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.Change; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.ChangeType; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.Engine; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.ManualChange; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.ManualRedactionType; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.Point; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.Rectangle; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogComment; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid; - -import io.micrometer.core.annotation.Timed; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Service -@RequiredArgsConstructor -public class RedactionLogMergeService { - - private static final String DELETED_TYPE_COLOR = "#9398a0"; - private final SectionTextService sectionTextService; - private final FileManagementStorageService fileManagementStorageService; - - - @Timed("redactmanager_getMergedRedactionLog") - public RedactionLog provideRedactionLog(RedactionRequest redactionRequest) { - - log.debug("Requested preview for: {}", redactionRequest); - - var redactionLog = fileManagementStorageService.getRedactionLog(redactionRequest.getDossierId(), redactionRequest.getFileId()); - - if (redactionLog == null) { - throw new NotFoundException("RedactionLog not present"); - } - - log.debug("Loaded redaction log with computationalVersion: {}", redactionLog.getAnalysisVersion()); - var merged = mergeRedactionLogData(redactionLog, - redactionRequest.getManualRedactions(), - redactionRequest.getExcludedPages(), - redactionRequest.getTypes(), - redactionRequest.getColors()); - - merged.getRedactionLogEntry().removeIf(e -> e.isFalsePositive() && !redactionRequest.isIncludeFalsePositives()); - - return merged; - } - - - private RedactionLog mergeRedactionLogData(RedactionLog redactionLog, ManualRedactions manualRedactions, Set excludedPages, List types, Colors colors) { - - var skippedImportedRedactions = new HashSet<>(); - log.info("Merging Redaction log with manual redactions"); - if (manualRedactions != null) { - - var manualRedactionWrappers = createManualRedactionWrappers(manualRedactions); - - for (RedactionLogEntry entry : redactionLog.getRedactionLogEntry()) { - var applicableManualRedactions = manualRedactionWrappers.stream().filter(mr -> entry.getId().equals(mr.getId())).collect(Collectors.toList()); - if (!applicableManualRedactions.isEmpty()) { - processRedactionLogEntry(applicableManualRedactions, entry, types, colors); - } - - if (entry.isImported() && !entry.isRedacted()) { - skippedImportedRedactions.add(entry.getId()); - } - - entry.setComments(convert(manualRedactions.getComments().get(entry.getId()))); - - if (excludedPages != null && !excludedPages.isEmpty()) { - entry.getPositions().forEach(pos -> { - if (!isLocalManualRedaction(entry) && excludedPages.contains(pos.getPage())) { - entry.setExcluded(true); - } - }); - } - } - - } - - Set processedIds = new HashSet<>(); - redactionLog.getRedactionLogEntry().removeIf(entry -> { - - if (entry.getImportedRedactionIntersections() != null) { - entry.getImportedRedactionIntersections().removeAll(skippedImportedRedactions); - if (!entry.getImportedRedactionIntersections().isEmpty() && (!entry.isImage() || entry.isImage() && !(entry.getType().equals("image") || entry.getType() - .equals("ocr")))) { - return true; - } - } - if (processedIds.contains(entry.getId())) { - log.info("Duplicate annotation found with id {}", entry.getId()); - return true; - } - processedIds.add(entry.getId()); - return false; - }); - return redactionLog; - } - - - private boolean isLocalManualRedaction(RedactionLogEntry entry) { - - return entry.getManualChanges() != null && entry.getManualChanges() - .stream() - .anyMatch(mc -> mc.getManualRedactionType() == ManualRedactionType.ADD_LOCALLY || mc.getManualRedactionType() == ManualRedactionType.RESIZE && mc.getAnnotationStatus() == AnnotationStatus.APPROVED && entry.getEngines() - .contains(Engine.RULE) && !entry.getEngines().contains(Engine.DICTIONARY)); - - } - - - private List createManualRedactionWrappers(ManualRedactions manualRedactions) { - - List manualRedactionWrappers = new ArrayList<>(); - - manualRedactions.getImageRecategorization().forEach(item -> { - if (item.getSoftDeletedTime() == null) { - manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)); - } - }); - - manualRedactions.getIdsToRemove().forEach(item -> { - if (item.getSoftDeletedTime() == null) { - manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)); - } - }); - - manualRedactions.getForceRedactions().forEach(item -> { - if (item.getSoftDeletedTime() == null) { - manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)); - } - }); - - manualRedactions.getLegalBasisChanges().forEach(item -> { - if (item.getSoftDeletedTime() == null) { - manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)); - } - }); - - manualRedactions.getResizeRedactions().forEach(item -> { - if (item.getSoftDeletedTime() == null) { - manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)); - } - }); - - Collections.sort(manualRedactionWrappers); - - return manualRedactionWrappers; - } - - - private void processRedactionLogEntry(List manualRedactionWrappers, RedactionLogEntry redactionLogEntry, List types, Colors colors) { - - manualRedactionWrappers.forEach(mrw -> { - - Object item = mrw.getItem(); - if (item instanceof ManualImageRecategorization) { - var imageRecategorization = (ManualImageRecategorization) item; - processManualRecategorization(redactionLogEntry, types, colors, imageRecategorization); - } - - if (item instanceof IdRemoval) { - var manualRemoval = (IdRemoval) item; - processIdRemoval(redactionLogEntry, types, colors, manualRemoval); - } - - if (item instanceof ManualForceRedaction) { - var manualForceRedact = (ManualForceRedaction) item; - processManualForceRedaction(redactionLogEntry, types, colors, manualForceRedact); - } - - if (item instanceof ManualLegalBasisChange) { - var manualLegalBasisChange = (ManualLegalBasisChange) item; - processManualLegalBasisChange(redactionLogEntry, types, colors, manualLegalBasisChange); - } - - if (item instanceof ManualResizeRedaction) { - var manualResizeRedact = (ManualResizeRedaction) item; - processManualResizeRedaction(redactionLogEntry, types, colors, manualResizeRedact); - } - - }); - - } - - - private void processManualRecategorization(RedactionLogEntry redactionLogEntry, List types, Colors colors, ManualImageRecategorization imageRecategorization) { - - String manualOverrideReason = null; - if (imageRecategorization.getStatus().equals(AnnotationStatus.APPROVED)) { - - redactionLogEntry.setType(imageRecategorization.getType()); - - if (isHint(types, imageRecategorization.getType())) { - redactionLogEntry.setRedacted(false); - redactionLogEntry.setHint(true); - } else { - redactionLogEntry.setHint(false); - } - - manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", recategorized by manual override"); - } else if (imageRecategorization.getStatus().equals(AnnotationStatus.REQUESTED)) { - manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to recategorize"); - redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, false, redactionLogEntry.isRedacted(), false, types)); - } - - if (manualOverrideReason != null) { - redactionLogEntry.setReason(manualOverrideReason); - } - - redactionLogEntry.getManualChanges() - .add(ManualChange.from(imageRecategorization).withManualRedactionType(ManualRedactionType.RECATEGORIZE).withChange("type", imageRecategorization.getType())); - } - - - private String mergeReasonIfNecessary(String currentReason, String addition) { - - if (currentReason != null) { - if (!currentReason.contains(addition)) { - return currentReason + addition; - } - return currentReason; - } else { - return ""; - } - } - - - private void processIdRemoval(RedactionLogEntry redactionLogEntry, List types, Colors colors, IdRemoval manualRemoval) { - - boolean isApprovedRedaction = manualRemoval.getStatus().equals(AnnotationStatus.APPROVED); - if (isApprovedRedaction && manualRemoval.isRemoveFromDictionary() && isBasedOnDictionaryOnly(redactionLogEntry)) { - log.debug("Skipping merge for dictionary-modifying entry"); - } else { - String redactionLogEntryType = redactionLogEntry.getType(); - String manualOverrideReason = null; - if (isApprovedRedaction) { - redactionLogEntry.setRedacted(false); - manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", removed by manual override"); - redactionLogEntry.setColor(getColor(redactionLogEntryType, colors, false, redactionLogEntry.isRedacted(), true, types)); - redactionLogEntry.setHint(false); - } else if (manualRemoval.getStatus().equals(AnnotationStatus.REQUESTED)) { - manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to remove"); - redactionLogEntry.setColor(getColor(redactionLogEntryType, colors, true, redactionLogEntry.isRedacted(), false, types)); - } - - if (manualOverrideReason != null) { - redactionLogEntry.setReason(manualOverrideReason); - } - } - - redactionLogEntry.getManualChanges() - .add(ManualChange.from(manualRemoval) - .withManualRedactionType(manualRemoval.isRemoveFromDictionary() ? ManualRedactionType.REMOVE_FROM_DICTIONARY : ManualRedactionType.REMOVE_LOCALLY)); - } - - - private boolean isBasedOnDictionaryOnly(RedactionLogEntry redactionLogEntry) { - - return redactionLogEntry.getEngines().contains(Engine.DICTIONARY) && redactionLogEntry.getEngines().size() == 1; - } - - - private void processManualForceRedaction(RedactionLogEntry redactionLogEntry, List types, Colors colors, ManualForceRedaction manualForceRedact) { - - String manualOverrideReason = null; - var dictionaryIsHint = isHint(types, redactionLogEntry.getType()); - if (manualForceRedact.getStatus().equals(AnnotationStatus.APPROVED)) { - // Forcing a skipped hint should result in a hint - if (dictionaryIsHint) { - redactionLogEntry.setHint(true); - } else { - redactionLogEntry.setRedacted(true); - } - redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, false, redactionLogEntry.isRedacted(), false, types)); - manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", forced by manual override"); - redactionLogEntry.setLegalBasis(manualForceRedact.getLegalBasis()); - } else if (manualForceRedact.getStatus().equals(AnnotationStatus.REQUESTED)) { - manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to force " + (dictionaryIsHint ? "hint" : "redact")); - redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, true, redactionLogEntry.isRedacted(), false, types)); - redactionLogEntry.setLegalBasis(manualForceRedact.getLegalBasis()); - } - - if (manualOverrideReason != null) { - redactionLogEntry.setReason(manualOverrideReason); - } - - var manualChange = ManualChange.from(manualForceRedact).withManualRedactionType(dictionaryIsHint ? ManualRedactionType.FORCE_HINT : ManualRedactionType.FORCE_REDACT); - - redactionLogEntry.getManualChanges().add(manualChange); - } - - - private void processManualLegalBasisChange(RedactionLogEntry redactionLogEntry, List types, Colors colors, ManualLegalBasisChange manualLegalBasisChange) { - - String manualOverrideReason = null; - if (manualLegalBasisChange.getStatus().equals(AnnotationStatus.APPROVED)) { - manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", legal basis was manually changed"); - redactionLogEntry.setLegalBasis(manualLegalBasisChange.getLegalBasis()); - redactionLogEntry.setRedacted(true); - if (manualLegalBasisChange.getSection() != null) { - redactionLogEntry.setSection(manualLegalBasisChange.getSection()); - } - if (redactionLogEntry.isRectangle() && manualLegalBasisChange.getValue() != null) { - redactionLogEntry.setValue(manualLegalBasisChange.getValue()); - } - } else if (manualLegalBasisChange.getStatus().equals(AnnotationStatus.REQUESTED)) { - manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", legal basis change requested"); - redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, true, redactionLogEntry.isRedacted(), false, types)); - } - - if (manualOverrideReason != null) { - redactionLogEntry.setReason(manualOverrideReason); - } - - var manualChange = ManualChange.from(manualLegalBasisChange).withManualRedactionType(ManualRedactionType.LEGAL_BASIS_CHANGE); - manualChange.withChange("legalBasis", manualLegalBasisChange.getLegalBasis()); - if (manualLegalBasisChange.getSection() != null) { - manualChange.withChange("section", manualLegalBasisChange.getSection()); - } - if (redactionLogEntry.isRectangle() && manualLegalBasisChange.getValue() != null) { - manualChange.withChange("value", manualLegalBasisChange.getValue()); - } - redactionLogEntry.getManualChanges().add(manualChange); - } - - - private void processManualResizeRedaction(RedactionLogEntry redactionLogEntry, List types, Colors colors, ManualResizeRedaction manualResizeRedact) { - - String manualOverrideReason = null; - if (manualResizeRedact.getStatus().equals(AnnotationStatus.APPROVED)) { - redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, false, redactionLogEntry.isRedacted(), false, types)); - redactionLogEntry.setPositions(convertPositions(manualResizeRedact.getPositions())); - if (!"signature".equalsIgnoreCase(redactionLogEntry.getType()) && !"logo".equalsIgnoreCase(redactionLogEntry.getType())) { - redactionLogEntry.setValue(manualResizeRedact.getValue()); - } - // This is for backwards compatibility, now the text after/before is calculated during reanalysis because we need to find dict entries on positions where entries are resized to smaller. - if (manualResizeRedact.getTextBefore() != null || manualResizeRedact.getTextAfter() != null) { - redactionLogEntry.setTextBefore(manualResizeRedact.getTextBefore()); - redactionLogEntry.setTextAfter(manualResizeRedact.getTextAfter()); - } - manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", resized by manual override"); - } else if (manualResizeRedact.getStatus().equals(AnnotationStatus.REQUESTED)) { - manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to resize redact"); - redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, true, redactionLogEntry.isRedacted(), false, types)); - redactionLogEntry.setPositions(convertPositions(manualResizeRedact.getPositions())); - - // This is for backwards compatibility, now the text after/before is calculated during reanalysis because we need to find dict entries on positions where entries are resized to smaller. - if (manualResizeRedact.getTextBefore() != null || manualResizeRedact.getTextAfter() != null) { - redactionLogEntry.setTextBefore(manualResizeRedact.getTextBefore()); - redactionLogEntry.setTextAfter(manualResizeRedact.getTextAfter()); - } - } - - redactionLogEntry.setReason(manualOverrideReason); - redactionLogEntry.getManualChanges() - .add(ManualChange.from(manualResizeRedact).withManualRedactionType(ManualRedactionType.RESIZE).withChange("value", manualResizeRedact.getValue())); - } - - - public List addManualAddEntries(SectionGrid sectionGrid, - Set manualAdds, - Map> comments, - Colors colors, - List types, - int analysisNumber) { - - List redactionLogEntries = new ArrayList<>(); - - for (ManualRedactionEntry manualRedactionEntry : manualAdds) { - - if (shouldCreateManualEntry(manualRedactionEntry)) { - RedactionLogEntry redactionLogEntry = createRedactionLogEntry(manualRedactionEntry, manualRedactionEntry.getAnnotationId(), colors, types, analysisNumber); - redactionLogEntry.setPositions(convertPositions(manualRedactionEntry.getPositions())); - redactionLogEntry.setComments(convert(comments.get(manualRedactionEntry.getAnnotationId()))); - redactionLogEntry.setTextBefore(manualRedactionEntry.getTextBefore()); - redactionLogEntry.setTextAfter(manualRedactionEntry.getTextAfter()); - - sectionTextService.handleSectionText(sectionGrid, redactionLogEntry); - - redactionLogEntries.add(redactionLogEntry); - } - } - - return redactionLogEntries; - } - - - private List convert(List comments) { - - return comments == null ? null : comments.stream() - .map(c -> new RedactionLogComment(c.getId(), c.getUser(), c.getText(), c.getAnnotationId(), c.getFileId(), c.getDate(), c.getSoftDeletedTime())) - .collect(Collectors.toList()); - } - - - private List convertPositions(List positions) { - - return positions.stream() - .map(pos -> new Rectangle(new Point(pos.getTopLeftX(), pos.getTopLeftY()), pos.getWidth(), pos.getHeight(), pos.getPage())) - .collect(Collectors.toList()); - } - - - @SuppressWarnings("PMD.UselessParentheses") - private boolean shouldCreateManualEntry(ManualRedactionEntry manualRedactionEntry) { - - return (!manualRedactionEntry.isAddToDictionary() && !manualRedactionEntry.isAddToDossierDictionary()) || ((manualRedactionEntry.isAddToDictionary() || manualRedactionEntry.isAddToDossierDictionary()) && manualRedactionEntry.getProcessedDate() == null); - } - - - private RedactionLogEntry createRedactionLogEntry(ManualRedactionEntry manualRedactionEntry, String id, Colors colors, List types, int analysisNumber) { - - var addToDictionary = manualRedactionEntry.isAddToDictionary() || manualRedactionEntry.isAddToDossierDictionary(); - - var change = ManualChange.from(manualRedactionEntry).withManualRedactionType(addToDictionary ? ManualRedactionType.ADD_TO_DICTIONARY : ManualRedactionType.ADD_LOCALLY); - List changeList = new ArrayList<>(); - changeList.add(change); - - return RedactionLogEntry.builder() - .id(id) - .color(getColorForManualAdd(manualRedactionEntry.getType(), colors, manualRedactionEntry.getStatus(), types)) - .reason(manualRedactionEntry.getReason()) - .isDictionaryEntry(manualRedactionEntry.isAddToDictionary()) - .isDossierDictionaryEntry(manualRedactionEntry.isAddToDossierDictionary()) - .legalBasis(manualRedactionEntry.getLegalBasis()) - .value(manualRedactionEntry.getValue()) - .sourceId(manualRedactionEntry.getSourceId()) - .section(manualRedactionEntry.getSection()) - .type(manualRedactionEntry.getType()) - .redacted(true) - .isHint(false) - .sectionNumber(-1) - .rectangle(manualRedactionEntry.isRectangle()) - .manualChanges(changeList) - .changes(List.of(new Change(analysisNumber + 1, ChangeType.ADDED, manualRedactionEntry.getRequestDate()))) - .build(); - } - - - private float[] getColor(String type, Colors colors, boolean requested, boolean isRedaction, boolean skipped, List types) { - - if (requested) { - return ColorUtils.convertColor(colors.getRequestRemoveColor()); - } - if (skipped || !isRedaction && !isHint(types, type)) { - return ColorUtils.convertColor(colors.getSkippedColor()); - } - return getColor(types, type); - } - - - private float[] getColorForManualAdd(String type, Colors colors, AnnotationStatus status, List types) { - - if (status.equals(AnnotationStatus.REQUESTED)) { - return ColorUtils.convertColor(colors.getRequestAddColor()); - } else if (status.equals(AnnotationStatus.DECLINED)) { - return ColorUtils.convertColor(colors.getSkippedColor()); - } - return getColor(types, type); - } - - - private float[] getColor(List types, String type) { - - var matchingTypes = getMatchingTypes(types, type); - Optional foundAndNotDeletedType = matchingTypes.stream().filter(t -> !isDeletedType(t)).findFirst(); - if (foundAndNotDeletedType.isPresent()) { - return ColorUtils.convertColor(foundAndNotDeletedType.get().getHexColor()); - } - Optional firstDeletedType = matchingTypes.stream().findFirst(); - return firstDeletedType.map(value -> ColorUtils.convertColor(value.getHexColor())).orElseGet(() -> ColorUtils.convertColor(DELETED_TYPE_COLOR)); - } - - - boolean isHint(List types, String type) { - - var matchingTypes = getMatchingTypes(types, type); - Optional foundAndNotDeletedType = matchingTypes.stream().filter(t -> !isDeletedType(t)).findFirst(); - if (foundAndNotDeletedType.isPresent()) { - return foundAndNotDeletedType.get().isHint(); - } - Optional firstDeletedType = matchingTypes.stream().findFirst(); - return firstDeletedType.map(Type::isHint).orElse(false); - } - - - private List getMatchingTypes(List types, String type) { - - return types.stream().filter(t -> t.getType().equals(type)).collect(Collectors.toList()); - } - - - private boolean isDeletedType(Type type) { - - return type.getSoftDeletedTime() != null; - } - - - @Data - @AllArgsConstructor - private static class ManualRedactionWrapper implements Comparable { - - private String id; - private OffsetDateTime date; - private Object item; - - - @Override - public int compareTo(ManualRedactionWrapper o) { - - return this.date.compareTo(o.date); - } - - } - -} - 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 cfbcaf2eb..f1736673a 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 @@ -155,4 +155,6 @@ databaseChangeLog: file: db/changelog/tenant/106-add-add-to-all-dossiers-to-resize-redactions.yaml - include: file: db/changelog/tenant/107-add-last-layout-processed-column.yaml + - include: + file: db/changelog/tenant/108-added-dictionary-changes-to-manual-recategorization.yaml diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/108-added-dictionary-changes-to-manual-recategorization.yaml b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/108-added-dictionary-changes-to-manual-recategorization.yaml new file mode 100644 index 000000000..ec01ac15f --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/108-added-dictionary-changes-to-manual-recategorization.yaml @@ -0,0 +1,79 @@ +databaseChangeLog: + - changeSet: + id: added-dictionary-changes-to-manual-recategorization + author: kilian + changes: + - addColumn: + columns: + - column: + name: add_to_dictionary + type: BOOLEAN + tableName: manual_image_recategorization + - addColumn: + columns: + - column: + name: add_to_all_dossiers + type: BOOLEAN + tableName: manual_image_recategorization + - changeSet: + id: added-dictionary-changes-to-manual-recategorization-2 + author: kilian + changes: + - createTable: + columns: + - column: + constraints: + nullable: false + name: manual_image_recategorization_entity_annotation_id + type: VARCHAR(255) + - column: + constraints: + nullable: false + name: manual_image_recategorization_entity_file_id + type: VARCHAR(255) + - column: + name: type_ids_of_dictionaries_with_add + type: VARCHAR(255) + tableName: manual_recategorization_type_ids_of_dictionaries_with_add + - createTable: + columns: + - column: + constraints: + nullable: false + name: manual_image_recategorization_entity_annotation_id + type: VARCHAR(255) + - column: + constraints: + nullable: false + name: manual_image_recategorization_entity_file_id + type: VARCHAR(255) + - column: + name: type_ids_of_dictionaries_with_delete + type: VARCHAR(255) + tableName: manual_recategorization_type_ids_of_dictionaries_with_delete + - changeSet: + id: added-dictionary-changes-to-manual-recategorization-3 + author: kilian + changes: + - addForeignKeyConstraint: + baseColumnNames: manual_image_recategorization_entity_annotation_id, manual_image_recategorization_entity_file_id + baseTableName: manual_recategorization_type_ids_of_dictionaries_with_add + constraintName: fk_manual_recategorization_to_dictionary_add + deferrable: false + initiallyDeferred: false + onDelete: NO ACTION + onUpdate: NO ACTION + referencedColumnNames: annotation_id, file_id + referencedTableName: manual_image_recategorization + validate: true + - addForeignKeyConstraint: + baseColumnNames: manual_image_recategorization_entity_annotation_id, manual_image_recategorization_entity_file_id + baseTableName: manual_recategorization_type_ids_of_dictionaries_with_delete + constraintName: fk_manual_recategorization_to_dictionary_delete + deferrable: false + initiallyDeferred: false + onDelete: NO ACTION + onUpdate: NO ACTION + referencedColumnNames: annotation_id, file_id + referencedTableName: manual_image_recategorization + validate: true \ 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/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 e6f9696fb..73a74774b 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 @@ -105,7 +105,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); - when(redactionLogMergeService.provideRedactionLog(Mockito.any())).thenReturn(redactionLog); + when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); Assertions.assertThrows(FeignException.Forbidden.class, () -> manualRedactionClient.removeRedactionBulk(dossier.getId(), @@ -254,7 +254,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); - when(redactionLogMergeService.provideRedactionLog(Mockito.any())).thenReturn(redactionLog); + when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), @@ -302,7 +302,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); - when(redactionLogMergeService.provideRedactionLog(Mockito.any())).thenReturn(redactionLog); + when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), @@ -343,7 +343,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); - when(redactionLogMergeService.provideRedactionLog(Mockito.any())).thenReturn(redactionLog); + when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), @@ -427,8 +427,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1); var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); - when(redactionLogMergeService.provideRedactionLog(redactionRequest1)).thenReturn(redactionLog1); - when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId(), true, true)).thenReturn(redactionLog1); + when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1); var redactionLog2 = new RedactionLog(1, 1, @@ -445,8 +444,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2); var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); - when(redactionLogMergeService.provideRedactionLog(redactionRequest2)).thenReturn(redactionLog2); - when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2); + when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2); // resize redaction in dossier 1 var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder() @@ -576,8 +574,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1); var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); - when(redactionLogMergeService.provideRedactionLog(redactionRequest1)).thenReturn(redactionLog1); - when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId(), true, true)).thenReturn(redactionLog1); + when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1); var redactionLog2 = new RedactionLog(1, 1, @@ -594,8 +591,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2); var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); - when(redactionLogMergeService.provideRedactionLog(redactionRequest2)).thenReturn(redactionLog2); - when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2); + when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2); // resize redaction in dossier 1 var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder() @@ -727,8 +723,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1); var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); - when(redactionLogMergeService.provideRedactionLog(redactionRequest1)).thenReturn(redactionLog1); - when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId(), true, true)).thenReturn(redactionLog1); + when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1); var redactionLog2 = new RedactionLog(1, 1, @@ -745,8 +740,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2); var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); - when(redactionLogMergeService.provideRedactionLog(redactionRequest2)).thenReturn(redactionLog2); - when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2); + when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2); // resize redaction in dossier dict var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder() @@ -875,8 +869,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1); var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); - when(redactionLogMergeService.provideRedactionLog(redactionRequest1)).thenReturn(redactionLog1); - when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId(), true, true)).thenReturn(redactionLog1); + when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1); var redactionLog2 = new RedactionLog(1, 1, @@ -893,8 +886,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0); fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2); var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); - when(redactionLogMergeService.provideRedactionLog(redactionRequest2)).thenReturn(redactionLog2); - when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2); + when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2); // resize redaction in dossier dict var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder() diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/RedactionLogTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/RedactionLogTest.java deleted file mode 100644 index 9a4977fd1..000000000 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/RedactionLogTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.iqser.red.service.peristence.v1.server.integration.tests; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.time.OffsetDateTime; - -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; - -import com.iqser.red.service.peristence.v1.server.integration.client.RedactionLogClient; -import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; -import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider; -import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.FilteredRedactionLogRequest; - -public class RedactionLogTest extends AbstractPersistenceServerServiceTest { - - @Autowired - private FileTesterAndProvider fileTesterAndProvider; - - @Autowired - private DossierTesterAndProvider dossierTesterAndProvider; - - @Autowired - private RedactionLogClient redactionLogClient; - - - @Test - public void testRedactionLog() { - - var dossier = dossierTesterAndProvider.provideTestDossier(); - var file = fileTesterAndProvider.testAndProvideFile(dossier); - - assertThat(redactionLogClient.getSectionGrid(dossier.getId(), file.getId())).isNotNull(); - assertThat(redactionLogClient.getRedactionLog(dossier.getId(), file.getId(), null, true, false)).isNotNull(); - assertThat(redactionLogClient.getRedactionLog(dossier.getId(), file.getId(), null, false, false)).isNotNull(); - assertThat(redactionLogClient.getFilteredRedactionLog(dossier.getId(), - file.getId(), - FilteredRedactionLogRequest.builder() - .excludedTypes(null) - .withManualRedactions(true) - .includeFalsePositives(false) - .specifiedDate(OffsetDateTime.now().minusDays(30)) - .build())).isNotNull(); - } - -} diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index b63d0438d..4c975313d 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -57,6 +57,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.configur import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles; import com.iqser.red.service.persistence.management.v1.processor.service.ApplicationConfigService; import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; +import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ApplicationConfigRepository; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.AuditRepository; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DigitalSignatureRepository; @@ -87,7 +88,6 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.EntryRepository; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalsePositiveEntryRepository; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalseRecommendationEntryRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.redactionlog.RedactionLogMergeService; import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.ApplicationConfig; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; @@ -123,7 +123,7 @@ public abstract class AbstractPersistenceServerServiceTest { @MockBean protected SearchClient searchClient; @MockBean - protected RedactionLogMergeService redactionLogMergeService; + protected RedactionLogService redactionLogService; @MockBean protected PDFTronClient pdfTronRedactionClient; @Autowired @@ -277,7 +277,7 @@ public abstract class AbstractPersistenceServerServiceTest { // doNothing().when(pdfTronRedactionClient).testDigitalCurrentSignature(Mockito.any()); when(amqpAdmin.getQueueInfo(Mockito.any())).thenReturn(null); - when(redactionLogMergeService.provideRedactionLog(Mockito.any())).thenReturn(new RedactionLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0)); + when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(new RedactionLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0)); when(redactionClient.testRules(Mockito.anyString())).thenReturn(DroolsSyntaxValidation.builder().compiled(true).droolsSyntaxErrorMessages(Collections.emptyList()).build()); } 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/AddRedactionRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AddRedactionRequest.java index 7ee98a327..e720bbc24 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AddRedactionRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AddRedactionRequest.java @@ -14,7 +14,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class AddRedactionRequest implements ManualRequestWithDictionary { +public class AddRedactionRequest implements ManualRequestWithAddToDictionary { private String user; private String dossierTemplateTypeId; 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/ManualRequestWithDictionary.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithAddToDictionary.java similarity index 79% rename from persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithDictionary.java rename to persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithAddToDictionary.java index 476f23113..200276fa5 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithDictionary.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithAddToDictionary.java @@ -2,9 +2,10 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.annotation import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; -public interface ManualRequestWithDictionary extends BaseManualRequest{ +public interface ManualRequestWithAddToDictionary extends BaseManualRequest { String getValue(); + String getDossierId(); boolean isAddToDictionary(); boolean isAddToAllDossiers(); boolean isForceAddToDictionary(); 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/ManualRequestWithRemoveFromDictionary.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithRemoveFromDictionary.java new file mode 100644 index 000000000..b04a26347 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithRemoveFromDictionary.java @@ -0,0 +1,13 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations; + +public interface ManualRequestWithRemoveFromDictionary extends BaseManualRequest { + + String getAnnotationId(); + + + boolean isRemoveFromDictionary(); + + + boolean isRemoveFromAllDossiers(); + +} 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/RecategorizationRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RecategorizationRequest.java index 43d234829..269047687 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RecategorizationRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RecategorizationRequest.java @@ -14,12 +14,13 @@ import lombok.experimental.FieldDefaults; @AllArgsConstructor @NoArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE) -public class RecategorizationRequest implements ManualRequestWithDictionary { +public class RecategorizationRequest implements ManualRequestWithAddToDictionary, ManualRequestWithRemoveFromDictionary { String annotationId; String user; AnnotationStatus status; - String typeId; + String dossierTemplateTypeId; + String dossierId; String comment; int page; String value; @@ -36,9 +37,16 @@ public class RecategorizationRequest implements ManualRequestWithDictionary { @Override - public String getDossierTemplateTypeId() { + public boolean isRemoveFromDictionary() { - return typeId; + return addToDictionary; + } + + + @Override + public boolean isRemoveFromAllDossiers() { + + return addToAllDossiers; } } 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/RemoveRedactionRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RemoveRedactionRequest.java index fbdf4b014..0dae857d2 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RemoveRedactionRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RemoveRedactionRequest.java @@ -9,7 +9,7 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class RemoveRedactionRequest implements BaseManualRequest{ +public class RemoveRedactionRequest implements ManualRequestWithRemoveFromDictionary { private String annotationId; private String user; -- 2.47.2 From ea5f79d67c12d2bb9d0fdf5aa6210f3471d34896 Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Wed, 30 Aug 2023 13:02:40 +0200 Subject: [PATCH 4/7] RED-7317: Endpoint to change entity types of dict-based annotations * added undo functionality * fixed tests * added recategorize with dictionary tests --- .../controller/ManualRedactionController.java | 27 +- .../DeleteRemovedManualAddRedactions7.java | 2 +- .../v1/processor/service/CommentService.java | 128 +++ .../processor/service/FileStatusService.java | 3 +- ...anualRedactionDictionaryUpdateHandler.java | 250 ++++-- .../ManualRedactionProviderService.java | 2 +- .../ManualRedactionService.java | 767 +++++------------- .../ManualRedactionUndoService.java | 153 +++- ...ageRecategorizationPersistenceService.java | 1 + .../ManualImageRecategorizationMapper.java | 4 +- .../integration/service/TypeProvider.java | 13 +- .../v1/server/integration/tests/FileTest.java | 126 +-- .../tests/ManualRedactionTest.java | 77 +- .../ManualRequestWithAddToDictionary.java | 11 +- .../annotations/RecategorizationRequest.java | 1 - 15 files changed, 863 insertions(+), 702 deletions(-) create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java rename persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/{ => manualredactions}/ManualRedactionProviderService.java (99%) 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 548846f37..8e4545d14 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 @@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RestController; import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService; import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService; +import com.iqser.red.service.persistence.management.v1.processor.service.CommentService; import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService; import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionUndoService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; @@ -44,22 +45,26 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.Remo import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel; import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; +import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; @Slf4j @RestController @RequiredArgsConstructor +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class ManualRedactionController implements ManualRedactionResource { - private static final String FILE_ID = "fileId"; - private static final String DOSSIER_ID = "dossierId"; - private static final String ANNOTATION_ID = "annotationId"; - private final ManualRedactionService manualRedactionService; - private final ManualRedactionUndoService manualRedactionUndoService; - private final DossierManagementService dossierManagementService; - private final AuditPersistenceService auditPersistenceService; - private final AccessControlService accessControlService; + final static String FILE_ID = "fileId"; + final static String DOSSIER_ID = "dossierId"; + final static String ANNOTATION_ID = "annotationId"; + ManualRedactionService manualRedactionService; + ManualRedactionUndoService manualRedactionUndoService; + DossierManagementService dossierManagementService; + AuditPersistenceService auditPersistenceService; + AccessControlService accessControlService; + CommentService commentService; @Override @@ -90,7 +95,7 @@ public class ManualRedactionController implements ManualRedactionResource { .message("Comment was removed.") .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) .build()); - manualRedactionService.deleteComment(dossierId, fileId, List.of(Long.valueOf(commentId))); + commentService.deleteComment(dossierId, fileId, List.of(Long.valueOf(commentId))); } @@ -107,7 +112,7 @@ public class ManualRedactionController implements ManualRedactionResource { @PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')") public Comments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { - return manualRedactionService.getComments(fileId); + return commentService.getComments(fileId); } @@ -121,7 +126,7 @@ public class ManualRedactionController implements ManualRedactionResource { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId); - var response = manualRedactionService.addComment(dossierId, + var response = commentService.addComment(dossierId, fileId, annotationId, CommentRequest.builder().user(KeycloakSecurity.getUserId()).text(addCommentRequest.getText()).build()); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DeleteRemovedManualAddRedactions7.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DeleteRemovedManualAddRedactions7.java index a072394e3..7ae908147 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DeleteRemovedManualAddRedactions7.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DeleteRemovedManualAddRedactions7.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Service; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.service.ManualRedactionProviderService; +import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java new file mode 100644 index 000000000..f5d5916ba --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java @@ -0,0 +1,128 @@ +package com.iqser.red.service.persistence.management.v1.processor.service; + +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.CommentEntity; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.CommentPersistenceService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus; +import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogComment; +import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; + +@Service +@RequiredArgsConstructor +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +public class CommentService { + + CommentPersistenceService commentPersistenceService; + FileStatusPersistenceService fileStatusPersistenceService; + FileStatusService fileStatusService; + RedactionLogService redactionLogService; + FileManagementStorageService fileManagementStorageService; + + + @Transactional + public void deleteComment(String dossierId, String fileId, List commentIds) { + + for (var commentId : commentIds) { + commentPersistenceService.softDelete(commentId, OffsetDateTime.now()); + } + // update indicator + fileStatusPersistenceService.updateHasComments(fileId, commentPersistenceService.fileHasComments(fileId)); + + // This is an ugly workaround, don't even look at it! + // Basically we should change how comments work and not merge them into the redaction log. + // if file is currently not analyzing, we can quickly change the redaction log, else we must wait for the analysis to finish. + if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { + reprocess(dossierId, fileId); + return; + } + fileStatusService.setStatusProcessing(fileId); + RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + redactionLog.getRedactionLogEntry().forEach(entry -> entry.getComments().removeIf(comment -> commentIds.contains(comment.getId()))); + fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); + fileStatusService.setStatusProcessed(fileId); + } + + + @Transactional + public Comments getComments(String fileId) { + + return new Comments(commentPersistenceService.findCommentsByFileID(fileId, false) + .entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> MagicConverter.convert(entry.getValue(), Comment.class)))); + } + + + @Transactional + public CommentEntity addComment(String dossierId, String fileId, String annotationId, CommentRequest commentRequest) { + + CommentEntity createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser()); + + fileStatusPersistenceService.updateHasComments(fileId, true); + + // This is an ugly workaround, don't even look at it! + // Basically we should change how comments work and not merge them into the redaction log. + if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { + reprocess(dossierId, fileId); + return createdComment; + } + fileStatusService.setStatusProcessing(fileId); + RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + redactionLog.getRedactionLogEntry() + .stream() + .filter(entry -> entry.getId().equals(annotationId)) + .forEach(entry -> entry.getComments().add(MagicConverter.convert(createdComment, RedactionLogComment.class))); + fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); + fileStatusService.setStatusProcessed(fileId); + return createdComment; + } + + + public Long addCommentAndGetId(String fileId, String annotationId, String comment, String user) { + + if (comment == null) { + return null; + } + return addComment(fileId, annotationId, comment, user).getId(); + } + + + private CommentEntity addComment(String fileId, String annotationId, String comment, String user) { + + if (comment == null) { + return null; + } + + return commentPersistenceService.insert(CommentEntity.builder() + .text(comment) + .fileId(fileId) + .annotationId(annotationId) + .user(user) + .date(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)) + .build()); + } + + + private void reprocess(String dossierId, String fileId) { + + fileStatusService.setStatusReprocessForManual(dossierId, fileId, true); + } + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java index d14a7d197..840becd04 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java @@ -3,7 +3,6 @@ package com.iqser.red.service.persistence.management.v1.processor.service; import static com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingQueueNames.LAYOUT_PARSING_REQUEST_QUEUE; import java.time.OffsetDateTime; -import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -13,7 +12,6 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.stereotype.Service; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Sets; import com.iqser.red.service.pdftron.redaction.v1.api.model.ProcessUntouchedDocumentRequest; import com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration; @@ -25,6 +23,7 @@ import com.iqser.red.service.persistence.management.v1.processor.model.NerServic import com.iqser.red.service.persistence.management.v1.processor.model.OCRStatusUpdateResponse; import com.iqser.red.service.persistence.management.v1.processor.model.image.ImageServiceRequest; import com.iqser.red.service.persistence.management.v1.processor.service.layoutparsing.LayoutParsingRequestFactory; +import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileAttributeConfigPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; 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 14d26e786..97a5e84b8 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 @@ -2,18 +2,26 @@ 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.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.springframework.stereotype.Service; +import com.iqser.red.service.dictionarymerge.commons.DictionaryEntry; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualResizeRedactionEntity; +import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; 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.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService; +import com.iqser.red.service.persistence.management.v1.processor.service.StopwordService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithAddToDictionary; @@ -23,71 +31,231 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import feign.FeignException; +import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; @Slf4j @Service @RequiredArgsConstructor +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class ManualRedactionDictionaryUpdateHandler { - private final DictionaryManagementService dictionaryManagementService; - private final AddRedactionPersistenceService addRedactionPersistenceService; - private final FileStatusPersistenceService fileStatusPersistenceService; - private final ResizeRedactionPersistenceService resizeRedactionPersistenceService; - private final DossierPersistenceService dossierPersistenceService; + DictionaryManagementService dictionaryManagementService; + DictionaryPersistenceService dictionaryPersistenceService; + FileStatusPersistenceService fileStatusPersistenceService; + ResizeRedactionPersistenceService resizeRedactionPersistenceService; + DossierPersistenceService dossierPersistenceService; + StopwordService stopwordService; - public Set handleAddToDictionaryAndReturnModifiedTypeIds(String fileId, String annotationId, ManualRequestWithAddToDictionary manualRequestWithAddToDictionary) { - - if (!manualRequestWithAddToDictionary.isApproved()) { - return null; - } + public Set handleAddToDictionaryAndReturnModifiedTypeIds(String fileId, String value, ManualRequestWithAddToDictionary manualRequestWithAddToDictionary) { if (!manualRequestWithAddToDictionary.isAddToDictionary()) { - addRedactionPersistenceService.updateStatus(fileId, annotationId, manualRequestWithAddToDictionary.getStatus(), false, null); - return null; + return Collections.emptySet(); } Set typeIdsOfModifiedDictionaries = new HashSet<>(); if (manualRequestWithAddToDictionary.isAddToAllDossiers()) { - var dictionaryEntriesToUnDelete = dictionaryManagementService.getAllEntriesInDossierTemplate(manualRequestWithAddToDictionary.getDossierTemplateTypeId(), - manualRequestWithAddToDictionary.getValue()); + List dictionaryEntriesToUnDelete = dictionaryManagementService.getAllEntriesInDossierTemplate(manualRequestWithAddToDictionary.getDossierTemplateTypeId(), + value); dictionaryEntriesToUnDelete.forEach(entry -> { typeIdsOfModifiedDictionaries.add(entry.getTypeId()); - addToDictionary(entry.getTypeId(), manualRequestWithAddToDictionary.getValue(), manualRequestWithAddToDictionary.getDossierId(), fileId, manualRequestWithAddToDictionary.getDictionaryEntryType()); + addToDictionary(entry.getTypeId(), + value, + manualRequestWithAddToDictionary.getDossierId(), + fileId, + manualRequestWithAddToDictionary.getDictionaryEntryType()); }); addToDictionary(manualRequestWithAddToDictionary.getDossierTemplateTypeId(), - manualRequestWithAddToDictionary.getValue(), + value, manualRequestWithAddToDictionary.getDossierId(), fileId, manualRequestWithAddToDictionary.getDictionaryEntryType()); typeIdsOfModifiedDictionaries.add(manualRequestWithAddToDictionary.getDossierTemplateTypeId()); - return typeIdsOfModifiedDictionaries; } addToDictionary(manualRequestWithAddToDictionary.getDossierTemplateTypeId() + ":" + manualRequestWithAddToDictionary.getDossierId(), - manualRequestWithAddToDictionary.getValue(), + value, manualRequestWithAddToDictionary.getDossierId(), fileId, manualRequestWithAddToDictionary.getDictionaryEntryType()); typeIdsOfModifiedDictionaries.add(manualRequestWithAddToDictionary.getDossierTemplateTypeId() + ":" + manualRequestWithAddToDictionary.getDossierId()); return typeIdsOfModifiedDictionaries; + } + + public Set handleRemoveFromDictionaryAndReturnModifiedTypeIds(RedactionLogEntry redactionLogEntry, + String fileId, + String dossierId, + String dossierTemplateId, + ManualRequestWithRemoveFromDictionary manualRequestWithRemoveFromDictionary) { + + if (!manualRequestWithRemoveFromDictionary.isRemoveFromDictionary()) { + + return Collections.emptySet(); + } + + Set typeIdsOfModifiedDictionaries = new HashSet<>(); + if (manualRequestWithRemoveFromDictionary.isRemoveFromAllDossiers()) { + var dictionaryEntriesToRemove = dictionaryManagementService.getAllEntriesInDossierTemplate(toTypeId(redactionLogEntry.getType(), dossierTemplateId), + redactionLogEntry.getValue()); + dictionaryEntriesToRemove.forEach(entry -> { + typeIdsOfModifiedDictionaries.add(entry.getTypeId()); + removeFromDictionary(entry.getTypeId(), entry.getValue(), dossierId, fileId, DictionaryEntryType.ENTRY); + }); + } else { + typeIdsOfModifiedDictionaries.add(toTypeId(redactionLogEntry.getType(), dossierTemplateId, dossierId)); + removeFromDictionary(toTypeId(redactionLogEntry.getType(), dossierTemplateId, dossierId), redactionLogEntry.getValue(), dossierId, fileId, DictionaryEntryType.ENTRY); + } + + // This is needed to remove resizeRedactions with addToDictionary. + removeResizeRedactionsWithAddToDictionary(dossierTemplateId, redactionLogEntry.getValue()); + + return typeIdsOfModifiedDictionaries; + } + + + public Set updateDictionaryForResizeRedactions(String dossierId, String fileId, ManualResizeRedactionEntity resizeRedaction, RedactionLogEntry redactionLogEntry) { + + if (resizeRedaction.getUpdateDictionary() != null && resizeRedaction.getUpdateDictionary() && resizeRedaction.getStatus() + .equals(AnnotationStatus.APPROVED) && (redactionLogEntry.isDictionaryEntry() || redactionLogEntry.isDossierDictionaryEntry())) { + + var dossier = dossierPersistenceService.findByDossierId(dossierId); + + var typeId = buildTypeId(redactionLogEntry, resizeRedaction, dossier); + var newValue = resizeRedaction.getValue(); + var oldValue = redactionLogEntry.getValue(); + var dictionaryEntryType = getDictionaryEntryType(redactionLogEntry); + + boolean isShrinking = oldValue != null && oldValue.length() > newValue.length(); + + Set typeIdsOfModifiedDictionaries = new HashSet<>(); + + if (isShrinking) { + log.info("Remove old value '{}' from dictionary", oldValue); + removeFromDictionary(typeId, oldValue, dossierId, fileId, dictionaryEntryType); + typeIdsOfModifiedDictionaries.add(typeId); + + if (resizeRedaction.isAddToAllDossiers() && redactionLogEntry.isDictionaryEntry()) { + String dossierTemplateId = dossier.getDossierTemplateId(); + var dossiersOfThisDossierTemplate = dossierPersistenceService.findAllDossiersForDossierTemplateId(dossierTemplateId); + var type = redactionLogEntry.getType(); + dossiersOfThisDossierTemplate.forEach(dossierEntity -> { + var typeIdOfDossierEntity = toTypeId(type, dossierTemplateId, dossierEntity.getId()); + removeFromDictionary(typeIdOfDossierEntity, oldValue, dossierId, fileId, dictionaryEntryType); + typeIdsOfModifiedDictionaries.add(typeIdOfDossierEntity); + }); + } + + } + + log.info("Add new value '{}' to dictionary", newValue); + addToDictionary(typeId, newValue, dossierId, fileId, dictionaryEntryType); + typeIdsOfModifiedDictionaries.add(typeId); + + return typeIdsOfModifiedDictionaries; + } + return Collections.emptySet(); + } + + + private String buildTypeId(RedactionLogEntry redactionLogEntry, ManualResizeRedactionEntity resizeRedaction, DossierEntity dossier) { + + if (resizeRedaction.isAddToAllDossiers()) { + return toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId()); + } else { + return toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId()); + } + + } + + + private DictionaryEntryType getDictionaryEntryType(RedactionLogEntry redactionLogEntry) { + + if (redactionLogEntry.isRecommendation() && redactionLogEntry.isFalsePositive()) { + return DictionaryEntryType.FALSE_RECOMMENDATION; + } else if (redactionLogEntry.isFalsePositive()) { + return DictionaryEntryType.FALSE_POSITIVE; + } else { + return DictionaryEntryType.ENTRY; + } } public boolean revertAddToDictionary(String fileId, String dossierId, ManualRedactionEntryEntity manualRedactionToRevert) { - if (!manualRedactionToRevert.getStatus().equals(AnnotationStatus.APPROVED) || manualRedactionToRevert.isAddToDictionary()) { + if (!manualRedactionToRevert.isAddToDictionary()) { return false; } - manualRedactionToRevert.getTypeIdsOfModifiedDictionaries().forEach(typeId -> { - removeFromDictionary(typeId, manualRedactionToRevert.getValue(), dossierId, fileId, manualRedactionToRevert.getDictionaryEntryType()); - }); + revertAddToDictionary(manualRedactionToRevert.getValue(), + manualRedactionToRevert.getDictionaryEntryType(), + fileId, + dossierId, + manualRedactionToRevert.getTypeIdsOfModifiedDictionaries()); return true; } + public void revertAddToDictionary(String value, DictionaryEntryType dictionaryEntryType, String fileId, String dossierId, Set typeIdsOfModifiedDictionaries) { + + typeIdsOfModifiedDictionaries.forEach(typeId -> { + removeFromDictionary(typeId, value, dossierId, fileId, dictionaryEntryType); + }); + } + + + public boolean revertRemoveFromDictionary(String value, String dossierId, String fileId, IdRemovalEntity idRemoval) { + + if (!idRemoval.isRemoveFromDictionary()) { + return false; + } + + revertRemoveFromDictionary(value, dossierId, fileId, idRemoval.getTypeIdsOfModifiedDictionaries()); + return true; + } + + + public void revertRemoveFromDictionary(String value, String dossierId, String fileId, Set typeIdsOfModifiedDictionaries) { + + typeIdsOfModifiedDictionaries.forEach(changedTypeId -> addToDictionary(changedTypeId, value, dossierId, fileId, DictionaryEntryType.ENTRY)); + } + + + public void validateDictionariesForDelete(ManualRequestWithRemoveFromDictionary request, RedactionLogEntry redactionLogEntry, String dossierTemplateId) { + + if (request.isRemoveFromDictionary()) { + var dossierTemplateTypeId = toTypeId(redactionLogEntry.getType(), dossierTemplateId); + dictionaryManagementService.validateAddRemoveToDossierTemplateDictionary(dossierTemplateTypeId, request.isRemoveFromDictionary(), request.isRemoveFromAllDossiers()); + } + } + + + public void validateDictionariesForAdd(ManualRequestWithAddToDictionary addRedactionRequest, String value) { + + if (addRedactionRequest.isAddToDictionary()) { + if (addRedactionRequest.isAddToAllDossiers()) { + // validate add to dossier template dictionaries + dictionaryManagementService.validateAddRemoveToDossierTemplateDictionary(addRedactionRequest.getDossierTemplateTypeId()); + } + validateDictionary(addRedactionRequest, value); + } + } + + + private void validateDictionary(ManualRequestWithAddToDictionary addRedactionRequest, String value) { + + try { + if (!addRedactionRequest.isForceAddToDictionary() && stopwordService.isStopword(value)) { + throw new ConflictException("The entry you are trying to add is a stopword"); + } + dictionaryPersistenceService.getType(addRedactionRequest.getDossierTemplateTypeId()); + } catch (NotFoundException e) { + throw new BadRequestException("Invalid type: " + addRedactionRequest.getDossierTemplateTypeId()); + } + } + + private void addToDictionary(String typeId, String value, String dossierId, String fileId, DictionaryEntryType dictionaryEntryType) { try { @@ -110,41 +278,6 @@ public class ManualRedactionDictionaryUpdateHandler { } - public Set handleRemoveFromDictionaryAndReturnModifiedTypeIds(RedactionLogEntry redactionLogEntry, - String fileId, - String dossierId, - String dossierTemplateId, - ManualRequestWithRemoveFromDictionary manualRequestWithRemoveFromDictionary) { - - if (!manualRequestWithRemoveFromDictionary.isApproved()) { - return null; - } - - if (!manualRequestWithRemoveFromDictionary.isRemoveFromDictionary()) { - - return null; - } - - Set typeIdsOfModifiedDictionaries = new HashSet<>(); - if (manualRequestWithRemoveFromDictionary.isRemoveFromAllDossiers()) { - var dictionaryEntriesToRemove = dictionaryManagementService.getAllEntriesInDossierTemplate(toTypeId(redactionLogEntry.getType(), dossierTemplateId), - redactionLogEntry.getValue()); - dictionaryEntriesToRemove.forEach(entry -> { - typeIdsOfModifiedDictionaries.add(entry.getTypeId()); - removeFromDictionary(entry.getTypeId(), entry.getValue(), dossierId, fileId, DictionaryEntryType.ENTRY); - }); - } else { - typeIdsOfModifiedDictionaries.add(toTypeId(redactionLogEntry.getType(), dossierTemplateId, dossierId)); - removeFromDictionary(toTypeId(redactionLogEntry.getType(), dossierTemplateId, dossierId), redactionLogEntry.getValue(), dossierId, fileId, DictionaryEntryType.ENTRY); - } - - // This is needed to remove resizeRedactions with addToDictionary. - removeResizeRedactionsWithAddToDictionary(dossierTemplateId, redactionLogEntry.getValue()); - - return typeIdsOfModifiedDictionaries; - } - - private void removeResizeRedactionsWithAddToDictionary(String dossierTemplateId, String redactionLogEntryValue) { var resizeRedactionsWithSameValue = resizeRedactionPersistenceService.findByAnnotationStatusAndValue(AnnotationStatus.APPROVED, redactionLogEntryValue); @@ -157,5 +290,4 @@ public class ManualRedactionDictionaryUpdateHandler { }); } - } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ManualRedactionProviderService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java similarity index 99% rename from persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ManualRedactionProviderService.java rename to persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java index 54511c53d..862cb9126 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ManualRedactionProviderService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java @@ -1,4 +1,4 @@ -package com.iqser.red.service.persistence.management.v1.processor.service; +package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions; import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter.convert; 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 c5f64a39d..2318b92f5 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 @@ -1,44 +1,24 @@ package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions; -import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId; - import java.nio.charset.StandardCharsets; -import java.time.OffsetDateTime; -import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.google.common.hash.HashFunction; import com.google.common.hash.Hashing; -import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.CommentEntity; -import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity; -import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualImageRecategorizationEntity; -import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; -import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualResizeRedactionEntity; -import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; 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.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.service.AnalysisFlagsCalculationService; +import com.iqser.red.service.persistence.management.v1.processor.service.CommentService; import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService; -import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; -import com.iqser.red.service.persistence.management.v1.processor.service.ManualRedactionProviderService; import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService; -import com.iqser.red.service.persistence.management.v1.processor.service.StopwordService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.CommentPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ForceRedactionPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ImageRecategorizationPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.LegalBasisChangePersistenceService; @@ -47,53 +27,44 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist 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.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.BaseManualRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; 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.ManualAddResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithAddToDictionary; 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.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.IdRemoval; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus; 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.redactionlog.RedactionLog; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogComment; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; -import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; import feign.FeignException; +import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; @Slf4j @Service @RequiredArgsConstructor +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class ManualRedactionService { - private final DossierPersistenceService dossierPersistenceService; - private final AddRedactionPersistenceService addRedactionPersistenceService; - private final RemoveRedactionPersistenceService removeRedactionPersistenceService; - private final ForceRedactionPersistenceService forceRedactionPersistenceService; - private final CommentPersistenceService commentPersistenceService; - private final FileStatusPersistenceService fileStatusPersistenceService; - private final DictionaryPersistenceService dictionaryPersistenceService; - private final FileManagementStorageService fileManagementStorageService; - private final ImageRecategorizationPersistenceService recategorizationPersistenceService; - private final LegalBasisChangePersistenceService legalBasisChangePersistenceService; - private final ResizeRedactionPersistenceService resizeRedactionPersistenceService; - private final FileStatusService fileStatusService; - private final ManualRedactionProviderService manualRedactionProviderService; - private final AnalysisFlagsCalculationService analysisFlagsCalculationService; - private final StopwordService stopwordService; - private final RedactionLogService redactionLogService; - private final DictionaryManagementService dictionaryManagementService; - private final HashFunction hashFunction = Hashing.murmur3_128(); - private final ManualRedactionDictionaryUpdateHandler manualRedactionDictionaryUpdateHandler; + DossierPersistenceService dossierPersistenceService; + AddRedactionPersistenceService addRedactionPersistenceService; + RemoveRedactionPersistenceService removeRedactionPersistenceService; + ForceRedactionPersistenceService forceRedactionPersistenceService; + CommentService commentService; + ImageRecategorizationPersistenceService recategorizationPersistenceService; + LegalBasisChangePersistenceService legalBasisChangePersistenceService; + ResizeRedactionPersistenceService resizeRedactionPersistenceService; + FileStatusService fileStatusService; + ManualRedactionProviderService manualRedactionProviderService; + AnalysisFlagsCalculationService analysisFlagsCalculationService; + RedactionLogService redactionLogService; + DictionaryManagementService dictionaryManagementService; + HashFunction hashFunction = Hashing.murmur3_128(); + ManualRedactionDictionaryUpdateHandler manualRedactionDictionaryUpdateHandler; @Transactional @@ -104,24 +75,22 @@ public class ManualRedactionService { dossierPersistenceService.getAndValidateDossier(dossierId); for (AddRedactionRequest addRedactionRequest : addRedactionRequests) { - validateDictionaries(addRedactionRequest); + manualRedactionDictionaryUpdateHandler.validateDictionariesForAdd(addRedactionRequest, addRedactionRequest.getValue()); validatePositions(fileId, addRedactionRequest); String annotationId = hashFunction.hashString(fileId + addRedactionRequest, StandardCharsets.UTF_8).toString(); addRedactionPersistenceService.insert(fileId, annotationId, addRedactionRequest); - Set typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.handleAddToDictionaryAndReturnModifiedTypeIds(fileId, - annotationId, - addRedactionRequest); + Set typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.handleAddToDictionaryAndReturnModifiedTypeIds(fileId, addRedactionRequest.getValue(), addRedactionRequest); addRedactionPersistenceService.updateStatus(fileId, annotationId, addRedactionRequest.getStatus(), - typeIdsOfModifiedDictionaries != null, + !typeIdsOfModifiedDictionaries.isEmpty(), typeIdsOfModifiedDictionaries); - Long commentId = addCommentAndGetId(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser()); + Long commentId = commentService.addCommentAndGetId(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser()); response.add(ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).build()); } @@ -136,28 +105,202 @@ public class ManualRedactionService { } - private void validateDictionaries(ManualRequestWithAddToDictionary addRedactionRequest) { + public List addRemoveRedaction(String dossierId, String fileId, List removeRedactionRequests) { - if (addRedactionRequest.isAddToDictionary()) { - if (addRedactionRequest.isAddToAllDossiers()) { - // validate add to dossier template dictionaries - dictionaryManagementService.validateAddRemoveToDossierTemplateDictionary(addRedactionRequest.getDossierTemplateTypeId()); + var response = new ArrayList(); + var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); + RedactionLog redactionLog = redactionLogService.getRedactionLog(dossier.getId(), fileId); + + var requiresReAnalysis = false; + var manualRedactions = manualRedactionProviderService.getManualRedactions(fileId); + + //validate removing from dossier template dictionary + + for (RemoveRedactionRequest removeRedactionRequest : removeRedactionRequests) { + RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId()); + manualRedactionDictionaryUpdateHandler.validateDictionariesForDelete(removeRedactionRequest, redactionLogEntry, dossier.getDossierTemplateId()); + + removeRedactionPersistenceService.insert(fileId, removeRedactionRequest); + + if (manualAddRedactionsContains(manualRedactions, removeRedactionRequest.getAnnotationId())) { + log.info("hard delete ManualRedactions for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId()); + manualRedactionProviderService.hardDeleteManualRedactions(fileId, removeRedactionRequest.getAnnotationId()); + requiresReAnalysis = true; + continue; } - validateDictionary(addRedactionRequest); + + log.info("add removeRedaction for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId()); + + Long commentId = commentService.addCommentAndGetId(fileId, + removeRedactionRequest.getAnnotationId(), + removeRedactionRequest.getComment(), + removeRedactionRequest.getUser()); + + Set typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.handleRemoveFromDictionaryAndReturnModifiedTypeIds(// + redactionLogEntry,// + fileId,// + dossierId, // + dossier.getDossierTemplateId(),// + removeRedactionRequest); + + boolean removedFromDictionary = !typeIdsOfModifiedDictionaries.isEmpty(); + + removeRedactionPersistenceService.updateStatus(fileId, + removeRedactionRequest.getAnnotationId(), + removeRedactionRequest.getStatus(), + removedFromDictionary, + typeIdsOfModifiedDictionaries); + + requiresReAnalysis = requiresReAnalysis || removedFromDictionary; + + response.add(ManualAddResponse.builder().annotationId(removeRedactionRequest.getAnnotationId()).commentId(commentId).build()); } + + if (requiresReAnalysis) { + reprocess(dossierId, fileId); + } + + analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + + return response; } - private void validateDictionary(ManualRequestWithAddToDictionary addRedactionRequest) { + @Transactional + public List addForceRedaction(String dossierId, String fileId, List forceRedactionRequests) { - try { - if (!addRedactionRequest.isForceAddToDictionary() && stopwordService.isStopword(addRedactionRequest.getValue())) { - throw new ConflictException("The entry you are trying to add is a stopword"); - } - dictionaryPersistenceService.getType(addRedactionRequest.getDossierTemplateTypeId()); - } catch (NotFoundException e) { - throw new BadRequestException("Invalid type: " + addRedactionRequest.getDossierTemplateTypeId()); + var response = new ArrayList(); + dossierPersistenceService.getAndValidateDossier(dossierId); + var requiresReanalysis = false; + + for (var forceRedactionRequest : forceRedactionRequests) { + forceRedactionPersistenceService.insert(fileId, forceRedactionRequest); + + Long commentId = commentService.addCommentAndGetId(fileId, + forceRedactionRequest.getAnnotationId(), + forceRedactionRequest.getComment(), + forceRedactionRequest.getUser()); + + requiresReanalysis = requiresReanalysis || forceRedactionRequest.isApproved(); + response.add(ManualAddResponse.builder().annotationId(forceRedactionRequest.getAnnotationId()).commentId(commentId).build()); } + + if (requiresReanalysis) { + reprocess(dossierId, fileId); + } + + analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + + return response; + } + + + @Transactional + public List addLegalBasisChange(String dossierId, String fileId, List legalBasisChangeRequests) { + + var response = new ArrayList(); + dossierPersistenceService.getAndValidateDossier(dossierId); + + for (var legalBasisChangeRequest : legalBasisChangeRequests) { + legalBasisChangePersistenceService.insert(fileId, legalBasisChangeRequest); + + Long commentId = commentService.addCommentAndGetId(fileId, + legalBasisChangeRequest.getAnnotationId(), + legalBasisChangeRequest.getComment(), + legalBasisChangeRequest.getUser()); + + response.add(ManualAddResponse.builder().annotationId(legalBasisChangeRequest.getAnnotationId()).commentId(commentId).build()); + } + analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + + return response; + } + + + @Transactional + public List addRecategorization(String dossierId, String fileId, List recategorizationRequests) { + + var response = new ArrayList(); + var requiresReanalysis = false; + var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); + RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + for (var recategorizationRequest : recategorizationRequests) { + RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, recategorizationRequest.getAnnotationId()); + manualRedactionDictionaryUpdateHandler.validateDictionariesForAdd(recategorizationRequest, redactionLogEntry.getValue()); + manualRedactionDictionaryUpdateHandler.validateDictionariesForDelete(recategorizationRequest, redactionLogEntry, dossier.getDossierTemplateId()); + + recategorizationPersistenceService.insert(fileId, recategorizationRequest); + + Set typeIdsOfDictionariesWithAdd = manualRedactionDictionaryUpdateHandler.handleAddToDictionaryAndReturnModifiedTypeIds(fileId, redactionLogEntry.getValue(), recategorizationRequest); + Set typeIdsOfDictionariesWithDelete = manualRedactionDictionaryUpdateHandler.handleRemoveFromDictionaryAndReturnModifiedTypeIds(redactionLogEntry, + fileId, + recategorizationRequest.getDossierId(), + dossier.getDossierTemplateId(), + recategorizationRequest); + + recategorizationPersistenceService.updateStatus(fileId, + recategorizationRequest.getAnnotationId(), + AnnotationStatus.APPROVED, + typeIdsOfDictionariesWithAdd != null, + typeIdsOfDictionariesWithAdd, + typeIdsOfDictionariesWithDelete); + + Long commentId = commentService.addCommentAndGetId(fileId, + recategorizationRequest.getAnnotationId(), + recategorizationRequest.getComment(), + recategorizationRequest.getUser()); + + requiresReanalysis = true; + + response.add(ManualAddResponse.builder().annotationId(recategorizationRequest.getAnnotationId()).commentId(commentId).build()); + } + if (requiresReanalysis) { + reprocess(dossierId, fileId); + } + + analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + + return response; + } + + + @Transactional + public List addResizeRedaction(String dossierId, String fileId, List resizeRedactionRequests) { + + List response = new ArrayList<>(); + + RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + + for (ResizeRedactionRequest resizeRedactionRequest : resizeRedactionRequests) { + + var resizeRedaction = resizeRedactionPersistenceService.insert(fileId, resizeRedactionRequest); + + if (resizeRedactionRequest.getComment() != null) { + Long commentId = commentService.addCommentAndGetId(fileId, + resizeRedactionRequest.getAnnotationId(), + resizeRedactionRequest.getComment(), + resizeRedactionRequest.getUser()); + response.add(ManualAddResponse.builder().annotationId(resizeRedactionRequest.getAnnotationId()).commentId(commentId).build()); + } + + Set typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.updateDictionaryForResizeRedactions(dossierId, + fileId, + resizeRedaction, + getRedactionLogEntry(redactionLog, resizeRedaction.getId().getAnnotationId())); + + resizeRedactionPersistenceService.updateStatus(resizeRedaction.getId().getFileId(), + resizeRedaction.getId().getAnnotationId(), + resizeRedaction.getStatus(), + typeIdsOfModifiedDictionaries); + } + + if (resizeRedactionRequests.stream().anyMatch(BaseManualRequest::isApproved)) { + reprocess(dossierId, fileId); + } + + analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + + return response; } @@ -168,43 +311,12 @@ public class ManualRedactionService { } - private Long addCommentAndGetId(String fileId, String annotationId, String comment, String user) { - - if (comment == null) { - return null; - } - return addComment(fileId, annotationId, comment, user).getId(); - } - - - private CommentEntity addComment(String fileId, String annotationId, String comment, String user) { - - if (comment == null) { - return null; - } - - return commentPersistenceService.insert(CommentEntity.builder() - .text(comment) - .fileId(fileId) - .annotationId(annotationId) - .user(user) - .date(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)) - .build()); - } - - private void reprocess(String dossierId, String fileId) { fileStatusService.setStatusReprocessForManual(dossierId, fileId, true); } - public ManualRedactionEntryEntity getAddRedaction(String fileId, String annotationId) { - - return addRedactionPersistenceService.findAddRedaction(fileId, annotationId); - } - - private void removeFromDictionary(String typeId, String value, String dossierId, String fileId, DictionaryEntryType dictionaryEntryType) { try { @@ -227,111 +339,12 @@ public class ManualRedactionService { } - public List addRemoveRedaction(String dossierId, String fileId, List removeRedactionRequests) { - - var response = new ArrayList(); - var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); - RedactionLog redactionLog = fileManagementStorageService.getRedactionLog(dossier.getId(), fileId); - - var requiresReAnalysis = false; - var manualRedactions = manualRedactionProviderService.getManualRedactions(fileId); - - //validate removing from dossier template dictionary - removeRedactionRequests.forEach(request -> { - if (request.isRemoveFromDictionary()) { - RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, request.getAnnotationId()); - var dossierTemplateTypeId = toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId()); - dictionaryManagementService.validateAddRemoveToDossierTemplateDictionary(dossierTemplateTypeId, - request.isRemoveFromDictionary(), - request.isRemoveFromAllDossiers()); - } - }); - - for (RemoveRedactionRequest removeRedactionRequest : removeRedactionRequests) { - - if (manualAddRedactionsContains(manualRedactions, removeRedactionRequest.getAnnotationId()) && removeRedactionRequest.getStatus().equals(AnnotationStatus.APPROVED)) { - log.info("hard delete ManualRedactions for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId()); - manualRedactionProviderService.hardDeleteManualRedactions(fileId, removeRedactionRequest.getAnnotationId()); - requiresReAnalysis = true; - continue; - } - - log.info("add removeRedaction for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId()); - IdRemoval idRemoval = MagicConverter.convert(removeRedactionPersistenceService.insert(fileId, removeRedactionRequest), IdRemoval.class); - - Long commentId = addCommentAndGetId(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getComment(), removeRedactionRequest.getUser()); - boolean matchingEntryFound = false; - if (!removeRedactionRequest.isRemoveFromDictionary() && AnnotationStatus.APPROVED.equals(removeRedactionRequest.getStatus())) { - try { - getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId()); - matchingEntryFound = true; - } catch (NotFoundException e) { - log.warn("No matching entry found in redaction log for annotation id {}", removeRedactionRequest.getAnnotationId()); - } - - requiresReAnalysis = requiresReAnalysis || matchingEntryFound; - } - - Set typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.handleRemoveFromDictionaryAndReturnModifiedTypeIds(// - getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId()),// - dossierId, // - dossier.getDossierTemplateId(),// - fileId, // - removeRedactionRequest); - - boolean removedFromDictionary = typeIdsOfModifiedDictionaries != null; - removeRedactionPersistenceService.updateStatus(fileId, - removeRedactionRequest.getAnnotationId(), - removeRedactionRequest.getStatus(), - removedFromDictionary, - typeIdsOfModifiedDictionaries); - - if (!matchingEntryFound && !removedFromDictionary && idRemoval.isApproved()) { - removeRedactionPersistenceService.markAsProcessed(idRemoval); - } - - requiresReAnalysis = requiresReAnalysis || removedFromDictionary; - - response.add(ManualAddResponse.builder().annotationId(removeRedactionRequest.getAnnotationId()).commentId(commentId).build()); - } - - if (requiresReAnalysis) { - reprocess(dossierId, fileId); - } - - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - - return response; - } - - private boolean manualAddRedactionsContains(ManualRedactions manualRedactions, String annotationId) { return manualRedactions.getEntriesToAdd().stream().anyMatch(m -> annotationId.equals(m.getAnnotationId())); } - private boolean revertRemoveFromDictionary(String value, DossierEntity dossier, String fileId, IdRemovalEntity idRemoval) { - - String annotationId = idRemoval.getId().getAnnotationId(); - - if (!idRemoval.getStatus().equals(AnnotationStatus.APPROVED)) { - return false; - } - if (!idRemoval.isRemoveFromDictionary()) { - removeRedactionPersistenceService.updateStatus(fileId, annotationId, idRemoval.getStatus(), false, Collections.emptySet()); - return false; - } - - idRemoval.getTypeIdsOfModifiedDictionaries().forEach(changedTypeId -> addToDictionary(changedTypeId, value, dossier.getId(), fileId, DictionaryEntryType.ENTRY)); - removeRedactionPersistenceService.updateStatus(fileId, annotationId, idRemoval.getStatus(), true, Collections.emptySet()); - return true; - } - - - - - private RedactionLogEntry getRedactionLogEntry(RedactionLog redactionLog, String annotationId) { return redactionLog.getRedactionLogEntry() @@ -342,355 +355,6 @@ public class ManualRedactionService { } - - @Transactional - public List addForceRedaction(String dossierId, String fileId, List forceRedactionRequests) { - - var response = new ArrayList(); - dossierPersistenceService.getAndValidateDossier(dossierId); - var requiresReanalysis = false; - - for (var forceRedactionRequest : forceRedactionRequests) { - forceRedactionPersistenceService.insert(fileId, forceRedactionRequest); - - Long commentId = addCommentAndGetId(fileId, forceRedactionRequest.getAnnotationId(), forceRedactionRequest.getComment(), forceRedactionRequest.getUser()); - - requiresReanalysis = requiresReanalysis || forceRedactionRequest.isApproved(); - response.add(ManualAddResponse.builder().annotationId(forceRedactionRequest.getAnnotationId()).commentId(commentId).build()); - } - - if (requiresReanalysis) { - reprocess(dossierId, fileId); - } - - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - - return response; - } - - - @Transactional - public List addLegalBasisChange(String dossierId, String fileId, List legalBasisChangeRequests) { - - var response = new ArrayList(); - dossierPersistenceService.getAndValidateDossier(dossierId); - - for (var legalBasisChangeRequest : legalBasisChangeRequests) { - legalBasisChangePersistenceService.insert(fileId, legalBasisChangeRequest); - - Long commentId = addCommentAndGetId(fileId, legalBasisChangeRequest.getAnnotationId(), legalBasisChangeRequest.getComment(), legalBasisChangeRequest.getUser()); - - response.add(ManualAddResponse.builder().annotationId(legalBasisChangeRequest.getAnnotationId()).commentId(commentId).build()); - } - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - - return response; - } - - - @Transactional - public List addRecategorization(String dossierId, String fileId, List recategorizationRequests) { - - var response = new ArrayList(); - var requiresReanalysis = false; - var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); - RedactionLog redactionLog = fileManagementStorageService.getRedactionLog(dossierId, fileId); - for (var recategorizationRequest : recategorizationRequests) { - validateDictionaries(recategorizationRequest); - - recategorizationPersistenceService.insert(fileId, recategorizationRequest); - - Set typeIdsOfDictionariesWithAdd = manualRedactionDictionaryUpdateHandler.handleAddToDictionaryAndReturnModifiedTypeIds(fileId, - recategorizationRequest.getAnnotationId(), - recategorizationRequest); - - Set typeIdsOfDictionariesWithDelete = manualRedactionDictionaryUpdateHandler.handleRemoveFromDictionaryAndReturnModifiedTypeIds(// - getRedactionLogEntry(redactionLog, recategorizationRequest.getAnnotationId()),// - recategorizationRequest.getDossierId(),// - dossier.getDossierTemplateId(),// - fileId,// - recategorizationRequest); - - recategorizationPersistenceService.updateStatus(fileId, - recategorizationRequest.getAnnotationId(), - AnnotationStatus.APPROVED, - typeIdsOfDictionariesWithAdd != null, - typeIdsOfDictionariesWithAdd, - typeIdsOfDictionariesWithDelete); - - Long commentId = addCommentAndGetId(fileId, recategorizationRequest.getAnnotationId(), recategorizationRequest.getComment(), recategorizationRequest.getUser()); - - requiresReanalysis = requiresReanalysis || recategorizationRequest.getStatus().equals(AnnotationStatus.APPROVED); - - response.add(ManualAddResponse.builder().annotationId(recategorizationRequest.getAnnotationId()).commentId(commentId).build()); - } - if (requiresReanalysis) { - reprocess(dossierId, fileId); - } - - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - - return response; - } - - - public CommentEntity addComment(String dossierId, String fileId, String annotationId, CommentRequest commentRequest) { - - CommentEntity createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser()); - - fileStatusPersistenceService.updateHasComments(fileId, true); - if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { - reprocess(dossierId, fileId); - return createdComment; - } - fileStatusService.setStatusProcessing(fileId); - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); - redactionLog.getRedactionLogEntry() - .stream() - .filter(entry -> entry.getId().equals(annotationId)) - .forEach(entry -> entry.getComments().add(MagicConverter.convert(createdComment, RedactionLogComment.class))); - fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); - fileStatusService.setStatusProcessed(fileId); - return createdComment; - } - - - @Transactional - public void deleteAddRedaction(String dossierId, String fileId, List annotationIds) { - - var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); - var requiresReanalysis = false; - - for (String annotationId : annotationIds) { - - ManualRedactionEntryEntity addRedaction = getAddRedaction(fileId, annotationId); - - boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertAddToDictionary(fileId, dossier.getId(), addRedaction); - requiresReanalysis = requiresReanalysis || dictionaryChanged; - addRedactionPersistenceService.updateStatus(fileId, annotationId, AnnotationStatus.APPROVED, false, null); - addRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - } - - if (requiresReanalysis) { - reprocess(dossierId, fileId); - } - - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - } - - - @Transactional - public void deleteRemoveRedaction(String dossierId, String fileId, List annotationIds) { - - var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); - var requiresReanalysis = false; - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); - - for (String annotationId : annotationIds) { - - IdRemovalEntity removeRedaction = getRemoveRedaction(fileId, annotationId); - String originalValue = getRedactionLogEntry(redactionLog, annotationId).getValue(); - boolean dictionaryChanged = revertRemoveFromDictionary(originalValue, dossier, fileId, removeRedaction); - - requiresReanalysis = requiresReanalysis || dictionaryChanged; - removeRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - } - - if (requiresReanalysis) { - reprocess(dossierId, fileId); - } - - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - } - - - private IdRemovalEntity getRemoveRedaction(String fileId, String annotationId) { - - return removeRedactionPersistenceService.findRemoveRedaction(fileId, annotationId); - } - - - @Transactional - public void deleteForceRedaction(String dossierId, String fileId, List annotationIds) { - - var now = OffsetDateTime.now(); - - for (var annotationId : annotationIds) { - forceRedactionPersistenceService.softDelete(fileId, annotationId, now); - } - - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - } - - - @Transactional - public void deleteLegalBasisChange(String dossierId, String fileId, List annotationIds) { - - for (var annotationId : annotationIds) { - legalBasisChangePersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - } - - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - } - - - @Transactional - public void deleteRecategorization(String dossierId, String fileId, List annotationIds) { - - var requiresReanalysis = false; - for (var annotationId : annotationIds) { - var imageRecategorization = getRecategorization(fileId, annotationId); - - recategorizationPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - - requiresReanalysis = requiresReanalysis || !AnnotationStatus.REQUESTED.equals(imageRecategorization.getStatus()); - } - - if (requiresReanalysis) { - reprocess(dossierId, fileId); - } - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - } - - - private ManualImageRecategorizationEntity getRecategorization(String fileId, String annotationId) { - - return recategorizationPersistenceService.findRecategorization(fileId, annotationId); - } - - - @Transactional - public void deleteComment(String dossierId, String fileId, List commentIds) { - - for (var commentId : commentIds) { - commentPersistenceService.softDelete(commentId, OffsetDateTime.now()); - } - // update indicator - fileStatusPersistenceService.updateHasComments(fileId, commentPersistenceService.fileHasComments(fileId)); - // if file is currently not analyzing, we can quickly change the redaction log, else we must wait for the analysis to finish. - if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { - reprocess(dossierId, fileId); - return; - } - fileStatusService.setStatusProcessing(fileId); - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); - redactionLog.getRedactionLogEntry().forEach(entry -> entry.getComments().removeIf(comment -> commentIds.contains(comment.getId()))); - fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); - fileStatusService.setStatusProcessed(fileId); - } - - - @Transactional - public void deleteResizeRedaction(String dossierId, String fileId, List annotationIds) { - - OffsetDateTime now = OffsetDateTime.now(); - for (var annotationId : annotationIds) { - resizeRedactionPersistenceService.softDelete(fileId, annotationId, now); - } - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - } - - - @Transactional - public List addResizeRedaction(String dossierId, String fileId, List resizeRedactionRequests) { - - List response = new ArrayList<>(); - - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); - - for (ResizeRedactionRequest resizeRedactionRequest : resizeRedactionRequests) { - - var resizeRedaction = resizeRedactionPersistenceService.insert(fileId, resizeRedactionRequest); - - if (resizeRedactionRequest.getComment() != null) { - Long commentId = addCommentAndGetId(fileId, resizeRedactionRequest.getAnnotationId(), resizeRedactionRequest.getComment(), resizeRedactionRequest.getUser()); - response.add(ManualAddResponse.builder().annotationId(resizeRedactionRequest.getAnnotationId()).commentId(commentId).build()); - } - - updateDictionaryForResizeRedactions(dossierId, fileId, resizeRedaction, redactionLog); - } - - if (resizeRedactionRequests.stream().anyMatch(BaseManualRequest::isApproved)) { - reprocess(dossierId, fileId); - } - - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - - return response; - } - - - private void updateDictionaryForResizeRedactions(String dossierId, String fileId, ManualResizeRedactionEntity resizeRedaction, RedactionLog redactionLog) { - - RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, resizeRedaction.getId().getAnnotationId()); - - if (resizeRedaction.getUpdateDictionary() != null && resizeRedaction.getUpdateDictionary() && resizeRedaction.getStatus() - .equals(AnnotationStatus.APPROVED) && (redactionLogEntry.isDictionaryEntry() || redactionLogEntry.isDossierDictionaryEntry())) { - - var dossier = dossierPersistenceService.findByDossierId(dossierId); - - var typeId = buildTypeId(redactionLogEntry, resizeRedaction, dossier); - var newValue = resizeRedaction.getValue(); - var oldValue = redactionLogEntry.getValue(); - var dictionaryEntryType = getDictionaryEntryType(redactionLogEntry); - - boolean isShrinking = oldValue != null && oldValue.length() > newValue.length(); - - Set typeIdsOfModifiedDictionaries = new HashSet<>(); - - if (isShrinking) { - log.info("Remove old value '{}' from dictionary", oldValue); - removeFromDictionary(typeId, oldValue, dossierId, fileId, dictionaryEntryType); - typeIdsOfModifiedDictionaries.add(typeId); - - if (resizeRedaction.isAddToAllDossiers() && redactionLogEntry.isDictionaryEntry()) { - String dossierTemplateId = dossier.getDossierTemplateId(); - var dossiersOfThisDossierTemplate = dossierPersistenceService.findAllDossiersForDossierTemplateId(dossierTemplateId); - var type = redactionLogEntry.getType(); - dossiersOfThisDossierTemplate.forEach(dossierEntity -> { - var typeIdOfDossierEntity = toTypeId(type, dossierTemplateId, dossierEntity.getId()); - removeFromDictionary(typeIdOfDossierEntity, oldValue, dossierId, fileId, dictionaryEntryType); - typeIdsOfModifiedDictionaries.add(typeIdOfDossierEntity); - }); - } - - } - - log.info("Add new value '{}' to dictionary", newValue); - addToDictionary(typeId, newValue, dossierId, fileId, dictionaryEntryType); - typeIdsOfModifiedDictionaries.add(typeId); - - resizeRedactionPersistenceService.updateStatus(resizeRedaction.getId().getFileId(), - resizeRedaction.getId().getAnnotationId(), - resizeRedaction.getStatus(), - typeIdsOfModifiedDictionaries); - } - } - - - private String buildTypeId(RedactionLogEntry redactionLogEntry, ManualResizeRedactionEntity resizeRedaction, DossierEntity dossier) { - - if (resizeRedaction.isAddToAllDossiers()) { - return toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId()); - } else { - return toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId()); - } - - } - - - private DictionaryEntryType getDictionaryEntryType(RedactionLogEntry redactionLogEntry) { - - if (redactionLogEntry.isRecommendation() && redactionLogEntry.isFalsePositive()) { - return DictionaryEntryType.FALSE_RECOMMENDATION; - } else if (redactionLogEntry.isFalsePositive()) { - return DictionaryEntryType.FALSE_POSITIVE; - } else { - return DictionaryEntryType.ENTRY; - } - } - - public ManualRedactions getManualRedactions(String fileId) { return manualRedactionProviderService.getManualRedactions(fileId); @@ -740,13 +404,4 @@ public class ManualRedactionService { } } - - public Comments getComments(String fileId) { - - return new Comments(commentPersistenceService.findCommentsByFileID(fileId, false) - .entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> MagicConverter.convert(entry.getValue(), Comment.class)))); - } - } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java index 6eac5cba6..67e23bd93 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java @@ -4,7 +4,9 @@ import static com.iqser.red.service.persistence.service.v1.api.external.resource import static com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource.DOSSIER_ID; import static com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource.FILE_ID; +import java.time.OffsetDateTime; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -13,11 +15,25 @@ import java.util.Set; import java.util.stream.Collectors; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualImageRecategorizationEntity; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; +import com.iqser.red.service.persistence.management.v1.processor.service.AnalysisFlagsCalculationService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; +import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ForceRedactionPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ImageRecategorizationPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.LegalBasisChangePersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService; import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction; @@ -26,24 +42,41 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations 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.annotations.entitymapped.ManualResizeRedaction; 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.type.DictionaryEntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ManualRedactionWrapperModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; +import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; @Service @RequiredArgsConstructor +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class ManualRedactionUndoService { - private final ManualRedactionService manualRedactionService; - private final AuditPersistenceService auditPersistenceService; - private final FileStatusService fileStatusService; + ManualRedactionProviderService manualRedactionProviderService; + AuditPersistenceService auditPersistenceService; + FileStatusService fileStatusService; + AnalysisFlagsCalculationService analysisFlagsCalculationService; + ImageRecategorizationPersistenceService recategorizationPersistenceService; + DossierPersistenceService dossierPersistenceService; + AddRedactionPersistenceService addRedactionPersistenceService; + RemoveRedactionPersistenceService removeRedactionPersistenceService; + ForceRedactionPersistenceService forceRedactionPersistenceService; + LegalBasisChangePersistenceService legalBasisChangePersistenceService; + ResizeRedactionPersistenceService resizeRedactionPersistenceService; + RedactionLogService redactionLogService; + ManualRedactionDictionaryUpdateHandler manualRedactionDictionaryUpdateHandler; + @Transactional public void undo(String dossierId, String fileId, Set annotationIds) { // undo the latest manual redaction for each annotationId - ManualRedactions manualRedactions = manualRedactionService.getManualRedactions(fileId); + ManualRedactions manualRedactions = getManualRedactions(fileId); Map manualRedactionWrappers = getLatestManualRedactionsForAnnotationIds(manualRedactions, annotationIds); @@ -60,6 +93,13 @@ public class ManualRedactionUndoService { reprocess(dossierId, fileId); } + + private ManualRedactions getManualRedactions(String fileId) { + + return manualRedactionProviderService.getManualRedactions(fileId); + } + + private void reprocess(String dossierId, String fileId) { fileStatusService.setStatusReprocessForManual(dossierId, fileId, true); @@ -74,7 +114,7 @@ public class ManualRedactionUndoService { .map(ManualRedactionWrapperModel::getId) .collect(Collectors.toList()); if (!manualResizeRedactions.isEmpty()) { - manualRedactionService.deleteResizeRedaction(dossierId, fileId, manualResizeRedactions); + deleteResizeRedaction(dossierId, fileId, manualResizeRedactions); manualResizeRedactions.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() .userId(KeycloakSecurity.getUserId()) .objectId(fileId) @@ -86,6 +126,16 @@ public class ManualRedactionUndoService { } + private void deleteResizeRedaction(String dossierId, String fileId, List annotationIds) { + + OffsetDateTime now = OffsetDateTime.now(); + for (var annotationId : annotationIds) { + resizeRedactionPersistenceService.softDelete(fileId, annotationId, now); + } + analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + } + + private void undoLegalBasisChange(String dossierId, String fileId, Map manualRedactionWrappers) { List manualLegalBasisChanges = manualRedactionWrappers.values() @@ -95,7 +145,7 @@ public class ManualRedactionUndoService { .collect(Collectors.toList()); if (!manualLegalBasisChanges.isEmpty()) { - manualRedactionService.deleteLegalBasisChange(dossierId, fileId, manualLegalBasisChanges); + deleteLegalBasisChange(dossierId, fileId, manualLegalBasisChanges); manualLegalBasisChanges.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() .userId(KeycloakSecurity.getUserId()) .objectId(fileId) @@ -107,6 +157,16 @@ public class ManualRedactionUndoService { } + private void deleteLegalBasisChange(String dossierId, String fileId, List annotationIds) { + + for (var annotationId : annotationIds) { + legalBasisChangePersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); + } + + analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + } + + private void undoRecategorization(String dossierId, String fileId, Map manualRedactionWrappers) { List manualImageRecategorizations = manualRedactionWrappers.values() @@ -116,7 +176,7 @@ public class ManualRedactionUndoService { .collect(Collectors.toList()); if (!manualImageRecategorizations.isEmpty()) { - manualRedactionService.deleteRecategorization(dossierId, fileId, manualImageRecategorizations); + deleteRecategorization(dossierId, fileId, manualImageRecategorizations); manualImageRecategorizations.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() .userId(KeycloakSecurity.getUserId()) .objectId(fileId) @@ -128,6 +188,22 @@ public class ManualRedactionUndoService { } + private void deleteRecategorization(String dossierId, String fileId, List annotationIds) { + + dossierPersistenceService.getAndValidateDossier(dossierId); + RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + + for (var annotationId : annotationIds) { + ManualImageRecategorizationEntity recategorizationEntity = recategorizationPersistenceService.findRecategorization(fileId, annotationId); + String originalValue = getRedactionLogEntry(redactionLog, annotationId).getValue(); + manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, recategorizationEntity.getTypeIdsOfDictionariesWithDelete()); + manualRedactionDictionaryUpdateHandler.revertAddToDictionary(originalValue, DictionaryEntryType.ENTRY, fileId, dossierId, recategorizationEntity.getTypeIdsOfDictionariesWithAdd()); + recategorizationPersistenceService.updateStatus(fileId, annotationId, AnnotationStatus.APPROVED, false, Collections.emptySet(), Collections.emptySet()); + recategorizationPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); + } analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + } + + private void undoForceRedactions(String dossierId, String fileId, Map manualRedactionWrappers) { List manualForceRedactions = manualRedactionWrappers.values() @@ -137,7 +213,7 @@ public class ManualRedactionUndoService { .collect(Collectors.toList()); if (!manualForceRedactions.isEmpty()) { - manualRedactionService.deleteForceRedaction(dossierId, fileId, manualForceRedactions); + deleteForceRedaction(dossierId, fileId, manualForceRedactions); manualForceRedactions.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() .userId(KeycloakSecurity.getUserId()) .objectId(fileId) @@ -149,6 +225,18 @@ public class ManualRedactionUndoService { } + private void deleteForceRedaction(String dossierId, String fileId, List annotationIds) { + + var now = OffsetDateTime.now(); + + for (var annotationId : annotationIds) { + forceRedactionPersistenceService.softDelete(fileId, annotationId, now); + } + + analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + } + + private void undoIdRemovals(String dossierId, String fileId, Map manualRedactionWrappers) { List idRemovals = manualRedactionWrappers.values() @@ -157,7 +245,7 @@ public class ManualRedactionUndoService { .map(ManualRedactionWrapperModel::getId) .collect(Collectors.toList()); if (!idRemovals.isEmpty()) { - manualRedactionService.deleteRemoveRedaction(dossierId, fileId, idRemovals); + deleteRemoveRedaction(dossierId, fileId, idRemovals); idRemovals.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() .userId(KeycloakSecurity.getUserId()) .objectId(fileId) @@ -169,6 +257,24 @@ public class ManualRedactionUndoService { } + private void deleteRemoveRedaction(String dossierId, String fileId, List annotationIds) { + + dossierPersistenceService.getAndValidateDossier(dossierId); + RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + + for (String annotationId : annotationIds) { + + IdRemovalEntity removeRedaction = removeRedactionPersistenceService.findRemoveRedaction(fileId, annotationId); + String originalValue = getRedactionLogEntry(redactionLog, annotationId).getValue(); + boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, removeRedaction); + removeRedactionPersistenceService.updateStatus(fileId, annotationId, removeRedaction.getStatus(), dictionaryChanged, Collections.emptySet()); + removeRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); + } + + analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + } + + private void undoManualRedactionEntries(String dossierId, String fileId, Map manualRedactionWrappers) { List manualRedactionEntries = manualRedactionWrappers.values() @@ -177,7 +283,7 @@ public class ManualRedactionUndoService { .map(ManualRedactionWrapperModel::getId) .collect(Collectors.toList()); if (!manualRedactionEntries.isEmpty()) { - manualRedactionService.deleteAddRedaction(dossierId, fileId, manualRedactionEntries); + deleteAddRedaction(dossierId, fileId, manualRedactionEntries); manualRedactionEntries.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() .userId(KeycloakSecurity.getUserId()) .objectId(fileId) @@ -189,6 +295,33 @@ public class ManualRedactionUndoService { } + private void deleteAddRedaction(String dossierId, String fileId, List annotationIds) { + + var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); + + for (String annotationId : annotationIds) { + + ManualRedactionEntryEntity addRedaction = addRedactionPersistenceService.findAddRedaction(fileId, annotationId); + + boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertAddToDictionary(fileId, dossier.getId(), addRedaction); + addRedactionPersistenceService.updateStatus(fileId, annotationId, AnnotationStatus.APPROVED, dictionaryChanged, null); + addRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); + } + + analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + } + + + private RedactionLogEntry getRedactionLogEntry(RedactionLog redactionLog, String annotationId) { + + return redactionLog.getRedactionLogEntry() + .stream() + .filter(entry -> entry.getId().equals(annotationId)) + .findFirst() + .orElseThrow(() -> new NotFoundException("Annotation does not exist in redaction log.")); + } + + private Map getLatestManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set annotationIds) { Map result = new HashMap<>(); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java index a2151494c..e3738e752 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ImageRecategorizationPersistenceService.java @@ -33,6 +33,7 @@ public class ImageRecategorizationPersistenceService { manualImageRecategorization.setId(new AnnotationEntityId(recategorizationRequest.getAnnotationId(), fileId)); BeanUtils.copyProperties(recategorizationRequest, manualImageRecategorization); manualImageRecategorization.setRequestDate(OffsetDateTime.now()); + manualImageRecategorization.setTypeId(recategorizationRequest.getDossierTemplateTypeId()); imageRecategorizationRepository.saveAndFlush(manualImageRecategorization); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/ManualImageRecategorizationMapper.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/ManualImageRecategorizationMapper.java index 567236630..6cac92b0d 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/ManualImageRecategorizationMapper.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/ManualImageRecategorizationMapper.java @@ -8,9 +8,9 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations public class ManualImageRecategorizationMapper implements BiConsumer { @Override - public void accept(ManualImageRecategorizationEntity manualRedactionEntryEntity, ManualImageRecategorization manualRedactionEntry) { + public void accept(ManualImageRecategorizationEntity manualImageRecategorizationEntity, ManualImageRecategorization manualRedactionEntry) { - manualRedactionEntry.setType(manualRedactionEntryEntity.getTypeId().substring(0, manualRedactionEntryEntity.getTypeId().indexOf(":"))); + manualRedactionEntry.setType(manualImageRecategorizationEntity.getTypeId().substring(0, manualImageRecategorizationEntity.getTypeId().indexOf(":"))); } } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/service/TypeProvider.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/service/TypeProvider.java index 44911a350..c245080bf 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/service/TypeProvider.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/service/TypeProvider.java @@ -2,8 +2,6 @@ package com.iqser.red.service.peristence.v1.server.integration.service; import static org.assertj.core.api.Assertions.assertThat; -import java.awt.Color; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -11,9 +9,7 @@ import com.iqser.red.service.peristence.v1.server.integration.client.DictionaryC import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue; import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeValue; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors; 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.Type; @Service public class TypeProvider { @@ -21,6 +17,7 @@ public class TypeProvider { @Autowired private DictionaryClient dictionaryClient; + public TypeValue testAndProvideType(DossierTemplateModel dossierTemplate) { return testAndProvideType(dossierTemplate, null, "test", false); @@ -32,9 +29,13 @@ public class TypeProvider { return testAndProvideType(dossierTemplate, dossier, typeName, false); } + public TypeValue testAndProvideType(DossierTemplateModel dossierTemplate, Dossier dossier, String typeName, boolean dossierDictionaryOnly) { + return testAndProvideType(dossierTemplate, dossier, typeName, dossierDictionaryOnly, 100); } + + public TypeValue testAndProvideType(DossierTemplateModel dossierTemplate, Dossier dossier, String typeName, boolean dossierDictionaryOnly, int rank) { var type = new CreateTypeValue(); @@ -53,9 +54,9 @@ public class TypeProvider { type.setDossierDictionaryOnly(dossierDictionaryOnly); dictionaryClient.addType(type); - var allTypes = dictionaryClient.getAllTypes(dossierTemplate.getDossierTemplateId(),dossier != null ? dossier.getId() : null,false); + var allTypes = dictionaryClient.getAllTypes(dossierTemplate.getDossierTemplateId(), dossier != null ? dossier.getId() : null, false); - var foundType =allTypes.getTypes().stream().filter(t -> t.getType().equalsIgnoreCase(typeName)).findAny(); + var foundType = allTypes.getTypes().stream().filter(t -> t.getType().equalsIgnoreCase(typeName)).findAny(); assertThat(foundType).isPresent(); return foundType.get(); 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 fbf87c741..fa626540e 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 @@ -1,32 +1,7 @@ package com.iqser.red.service.peristence.v1.server.integration.tests; -import com.google.common.collect.Sets; -import com.google.common.hash.HashFunction; -import com.google.common.hash.Hashing; -import com.iqser.red.service.peristence.v1.server.integration.client.*; -import com.iqser.red.service.peristence.v1.server.integration.service.*; -import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; -import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; -import com.iqser.red.service.persistence.service.v1.api.shared.model.*; -import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive; -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.dossier.file.FileAttributeConfig; -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.dossier.file.ProcessingStatus; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; -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; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; - -import feign.FeignException; -import lombok.SneakyThrows; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.mock.web.MockMultipartFile; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; @@ -36,7 +11,58 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockMultipartFile; + +import com.google.common.collect.Sets; +import com.google.common.hash.HashFunction; +import com.google.common.hash.Hashing; +import com.iqser.red.service.peristence.v1.server.integration.client.DossierClient; +import com.iqser.red.service.peristence.v1.server.integration.client.DossierTemplateClient; +import com.iqser.red.service.peristence.v1.server.integration.client.FileAttributeClient; +import com.iqser.red.service.peristence.v1.server.integration.client.FileAttributeConfigClient; +import com.iqser.red.service.peristence.v1.server.integration.client.FileClient; +import com.iqser.red.service.peristence.v1.server.integration.client.FileManagementClient; +import com.iqser.red.service.peristence.v1.server.integration.client.ManualRedactionClient; +import com.iqser.red.service.peristence.v1.server.integration.client.ReanalysisClient; +import com.iqser.red.service.peristence.v1.server.integration.client.RedactionLogClient; +import com.iqser.red.service.peristence.v1.server.integration.client.UploadClient; +import com.iqser.red.service.peristence.v1.server.integration.client.ViewedPagesClient; +import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.TypeProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.UserProvider; +import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; +import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributes; +import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributesConfig; +import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus; +import com.iqser.red.service.persistence.service.v1.api.shared.model.FileUploadResult; +import com.iqser.red.service.persistence.service.v1.api.shared.model.PageExclusionRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.PageRange; +import com.iqser.red.service.persistence.service.v1.api.shared.model.ViewedPagesRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive; +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.dossier.file.FileAttributeConfig; +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.dossier.file.ProcessingStatus; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; +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; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; + +import feign.FeignException; +import lombok.SneakyThrows; public class FileTest extends AbstractPersistenceServerServiceTest { @@ -103,7 +129,6 @@ public class FileTest extends AbstractPersistenceServerServiceTest { assertThat(fileClient.getDossierStatus(dossier.getId()).size()).isEqualTo(1); var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); - fileManagementClient.deleteFile(dossier.getId(), file.getId()); var nrOfFiles = fileClient.getSoftDeletedDossierStatus(dossier.getId()).size(); @@ -330,31 +355,37 @@ public class FileTest extends AbstractPersistenceServerServiceTest { var type = typeProvider.testAndProvideType(dossierTemplate, null, "manual"); + var annotationId = "imagine_this_makes_sense"; + RedactionLog redactionLog = new RedactionLog(); + RedactionLogEntry redactionLogEntry = RedactionLogEntry.builder().type(type.getType()).id(annotationId).build(); + redactionLog.getRedactionLogEntry().add(redactionLogEntry); + + when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); + assertThat(fileClient.getDossierStatus(dossier.getId()).size()).isEqualTo(1); - var addRedaction = manualRedactionClient.addRedactionBulk(dossierId, - fileId, - Set.of(AddRedactionRequestModel.builder() - .addToDictionary(true) - .type(type.getType()) - .addToAllDossiers(true) - .reason("1") - .value("test") - .legalBasis("1") - .dictionaryEntryType(DictionaryEntryType.ENTRY) - .build())).iterator().next(); + var addRedactionRequest = AddRedactionRequestModel.builder() + .addToDictionary(true) + .type(type.getType()) + .addToAllDossiers(true) + .reason("1") + .value("test") + .legalBasis("1") + .build(); + manualRedactionClient.addRedactionBulk(dossierId, fileId, Set.of(addRedactionRequest)); + manualRedactionClient.removeRedactionBulk(dossierId, fileId, - Set.of(RemoveRedactionRequestModel.builder().annotationId(addRedaction.getAnnotationId()).comment("comment").removeFromDictionary(false).build())); + Set.of(RemoveRedactionRequestModel.builder().annotationId(annotationId).comment("comment").removeFromDictionary(false).build())); manualRedactionClient.forceRedactionBulk(dossierId, fileId, Set.of(ForceRedactionRequestModel.builder().annotationId("forceRedactionAnnotation").comment("comment").legalBasis("1").build())); - manualRedactionClient.legalBasisChangeBulk(dossierId, + manualRedactionClient.legalBasisChangeBulk(dossierId, fileId, Set.of(LegalBasisChangeRequestModel.builder().annotationId("legalBasisChangeAnnotation").comment("comment").legalBasis("1").build())); manualRedactionClient.recategorizeBulk(dossierId, fileId, - Set.of(RecategorizationRequestModel.builder().annotationId("imageRecategorizationAnnotation").comment("comment").type("new-type").build())); + Set.of(RecategorizationRequestModel.builder().annotationId(annotationId).comment("comment").type("new-type").build())); var loadedFile = fileClient.getFileStatus(dossierId, fileId); @@ -409,12 +440,10 @@ public class FileTest extends AbstractPersistenceServerServiceTest { .reason("1") .value("test") .legalBasis("1") - .dictionaryEntryType(DictionaryEntryType.ENTRY) .build())).iterator().next(); var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); - reanalysisClient.toggleExclusion(dossier.getId(), file.getId(), true); loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); assertThat(loadedFile.isExcluded()).isTrue(); @@ -438,7 +467,6 @@ public class FileTest extends AbstractPersistenceServerServiceTest { var file = fileTesterAndProvider.testAndProvideFile(dossier, fileName); String fileId = file.getId(); - var type = typeProvider.testAndProvideType(dossierTemplate, null, "manual"); assertThat(fileClient.getDossierStatus(dossier.getId()).size()).isEqualTo(1); @@ -515,6 +543,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest { } + @Test public void testFile6034SetUnderReview() { @@ -542,17 +571,15 @@ public class FileTest extends AbstractPersistenceServerServiceTest { assertThat(actualMessage).contains(expectedMessage); - exception = Assertions.assertThrows(FeignException.BadRequest.class, () -> { fileClient.setStatusUnderReview(dossier.getId(), file.getId(), user2); }); expectedMessage = "User must be dossier member"; - actualMessage = exception.getMessage(); + actualMessage = exception.getMessage(); assertThat(actualMessage).contains(expectedMessage); - fileClient.setStatusUnderReview(dossier.getId(), file.getId(), altUserId); loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); assertThat(loadedFile.getWorkflowStatus()).isEqualTo(WorkflowStatus.UNDER_REVIEW); @@ -561,6 +588,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest { assertThat(loadedFile.getLastApprover()).isNull(); } + @Test @SneakyThrows public void testUploadFileIsInOcrProcessingWithOcrByDefaultFlagTrue() { 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 73a74774b..ab73a294a 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 @@ -13,10 +13,12 @@ import com.iqser.red.service.persistence.management.v1.processor.service.Redacti import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.redactionlog.RedactionRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.Dictionary; 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.RecategorizationRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; @@ -238,10 +240,10 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getDossierId(), DictionaryEntryType.ENTRY); - var dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); + Dictionary dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker", "Darth Vader"); - var dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker"); var redactionLog = new RedactionLog(1, @@ -258,7 +260,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), - Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())).get(0); + Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())); dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Darth Vader"); @@ -948,4 +950,73 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template"); } + @Test + public void testManualRecategorizeAndUndo() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + + var type = typeProvider.testAndProvideType(dossierTemplate); + var type2 = typeProvider.testAndProvideType(dossierTemplate, dossier, "test2", false, 66); + + var entries = new ArrayList(); + + var lukeSkywalker = "Luke Skywalker"; + var darthVader = "Darth Vader"; + entries.add(lukeSkywalker); + entries.add(darthVader); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), entries, false, null, DictionaryEntryType.ENTRY); + + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of(lukeSkywalker), false, dossier.getDossierId(), DictionaryEntryType.ENTRY); + + Dictionary dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); + assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader); + Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker); + + Dictionary dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null); + assertThat(dossierTemplateDictionary2.getEntries()).isEmpty(); + Dictionary dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + assertThat(dossierDictionary2.getEntries()).isEmpty(); + + var annotationId = "AnnotationId"; + var redactionLog = new RedactionLog(1, + 1, + List.of(RedactionLogEntry.builder().id(annotationId).type(type.getType()).value(lukeSkywalker).isDictionaryEntry(true).build()), + null, + 0, + 0, + 0, + 0); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); + + when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); + + manualRedactionClient.recategorizeBulk(dossier.getId(), + file.getId(), + Set.of(RecategorizationRequestModel.builder().type(type2.getType()).annotationId(annotationId).addToDictionary(true).addToAllDossiers(true).build())); + + dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); + assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(darthVader); + dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + assertThat(dossierDictionary.getEntries()).isEmpty(); + + dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null); + assertThat(dossierTemplateDictionary2.getEntries()).containsExactlyInAnyOrder(lukeSkywalker); + dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + assertThat(dossierDictionary2.getEntries()).containsExactlyInAnyOrder(lukeSkywalker); + + manualRedactionClient.undo(dossier.getDossierId(), file.getFileId(), Set.of(annotationId)); + + dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); + assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader); + dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker); + + dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null); + assertThat(dossierTemplateDictionary2.getEntries()).isEmpty(); + dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + assertThat(dossierDictionary2.getEntries()).isEmpty(); + } } 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/ManualRequestWithAddToDictionary.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithAddToDictionary.java index 200276fa5..d06ef8539 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithAddToDictionary.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRequestWithAddToDictionary.java @@ -4,12 +4,21 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp public interface ManualRequestWithAddToDictionary extends BaseManualRequest { - String getValue(); String getDossierId(); + + boolean isAddToDictionary(); + + boolean isAddToAllDossiers(); + + boolean isForceAddToDictionary(); + + String getDossierTemplateTypeId(); + + DictionaryEntryType getDictionaryEntryType(); } 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/RecategorizationRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RecategorizationRequest.java index 269047687..1a7e371a3 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RecategorizationRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/RecategorizationRequest.java @@ -23,7 +23,6 @@ public class RecategorizationRequest implements ManualRequestWithAddToDictionary String dossierId; String comment; int page; - String value; boolean addToDictionary; boolean addToAllDossiers; private DictionaryEntryType dictionaryEntryType; -- 2.47.2 From d25b8c39344f41c3b566fc1a8974f6f3e91f4dba Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Wed, 30 Aug 2023 14:51:50 +0200 Subject: [PATCH 5/7] RED-7317: Endpoint to change entity types of dict-based annotations * fixed tests --- ...anualRedactionDictionaryUpdateHandler.java | 47 ++++++++++++------- .../tests/ManualRedactionTest.java | 2 +- 2 files changed, 31 insertions(+), 18 deletions(-) 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 97a5e84b8..5df5433ff 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 @@ -57,23 +57,37 @@ public class ManualRedactionDictionaryUpdateHandler { } Set typeIdsOfModifiedDictionaries = new HashSet<>(); if (manualRequestWithAddToDictionary.isAddToAllDossiers()) { - List dictionaryEntriesToUnDelete = dictionaryManagementService.getAllEntriesInDossierTemplate(manualRequestWithAddToDictionary.getDossierTemplateTypeId(), - value); - dictionaryEntriesToUnDelete.forEach(entry -> { - typeIdsOfModifiedDictionaries.add(entry.getTypeId()); - addToDictionary(entry.getTypeId(), - value, - manualRequestWithAddToDictionary.getDossierId(), - fileId, - manualRequestWithAddToDictionary.getDictionaryEntryType()); - }); - addToDictionary(manualRequestWithAddToDictionary.getDossierTemplateTypeId(), - value, - manualRequestWithAddToDictionary.getDossierId(), - fileId, - manualRequestWithAddToDictionary.getDictionaryEntryType()); - typeIdsOfModifiedDictionaries.add(manualRequestWithAddToDictionary.getDossierTemplateTypeId()); + return addToDossierTemplateDictionary(fileId, value, manualRequestWithAddToDictionary, typeIdsOfModifiedDictionaries); } + return addToDossierDictionary(fileId, value, manualRequestWithAddToDictionary, typeIdsOfModifiedDictionaries); + } + + + + + private Set addToDossierTemplateDictionary(String fileId, String value, ManualRequestWithAddToDictionary manualRequestWithAddToDictionary, Set typeIdsOfModifiedDictionaries) { + + List dictionaryEntriesToUnDelete = dictionaryManagementService.getAllEntriesInDossierTemplate(manualRequestWithAddToDictionary.getDossierTemplateTypeId(), + value); + dictionaryEntriesToUnDelete.forEach(entry -> { + typeIdsOfModifiedDictionaries.add(entry.getTypeId()); + addToDictionary(entry.getTypeId(), value, + manualRequestWithAddToDictionary.getDossierId(), fileId, + manualRequestWithAddToDictionary.getDictionaryEntryType()); + }); + addToDictionary(manualRequestWithAddToDictionary.getDossierTemplateTypeId(), value, + manualRequestWithAddToDictionary.getDossierId(), fileId, + manualRequestWithAddToDictionary.getDictionaryEntryType()); + typeIdsOfModifiedDictionaries.add(manualRequestWithAddToDictionary.getDossierTemplateTypeId()); + return typeIdsOfModifiedDictionaries; + } + + + private Set addToDossierDictionary(String fileId, + String value, + ManualRequestWithAddToDictionary manualRequestWithAddToDictionary, + Set typeIdsOfModifiedDictionaries) { + addToDictionary(manualRequestWithAddToDictionary.getDossierTemplateTypeId() + ":" + manualRequestWithAddToDictionary.getDossierId(), value, manualRequestWithAddToDictionary.getDossierId(), @@ -83,7 +97,6 @@ public class ManualRedactionDictionaryUpdateHandler { return typeIdsOfModifiedDictionaries; } - public Set handleRemoveFromDictionaryAndReturnModifiedTypeIds(RedactionLogEntry redactionLogEntry, String fileId, String dossierId, 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 ab73a294a..5c973e35d 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 @@ -1005,7 +1005,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary2.getEntries()).containsExactlyInAnyOrder(lukeSkywalker); dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId()); - assertThat(dossierDictionary2.getEntries()).containsExactlyInAnyOrder(lukeSkywalker); + assertThat(dossierDictionary2.getEntries()).isEmpty(); manualRedactionClient.undo(dossier.getDossierId(), file.getFileId(), Set.of(annotationId)); -- 2.47.2 From 80e602fb074a4c7dbdfa0d1a30b71dca574e7adc Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Wed, 30 Aug 2023 15:32:22 +0200 Subject: [PATCH 6/7] RED-7317: Endpoint to change entity types of dict-based annotations * rebased --- .../ManualRedactionDictionaryUpdateHandler.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) 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 5df5433ff..4c07842f9 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 @@ -68,7 +68,7 @@ public class ManualRedactionDictionaryUpdateHandler { private Set addToDossierTemplateDictionary(String fileId, String value, ManualRequestWithAddToDictionary manualRequestWithAddToDictionary, Set typeIdsOfModifiedDictionaries) { List dictionaryEntriesToUnDelete = dictionaryManagementService.getAllEntriesInDossierTemplate(manualRequestWithAddToDictionary.getDossierTemplateTypeId(), - value); + value, manualRequestWithAddToDictionary.getDictionaryEntryType()); dictionaryEntriesToUnDelete.forEach(entry -> { typeIdsOfModifiedDictionaries.add(entry.getTypeId()); addToDictionary(entry.getTypeId(), value, @@ -111,7 +111,7 @@ public class ManualRedactionDictionaryUpdateHandler { Set typeIdsOfModifiedDictionaries = new HashSet<>(); if (manualRequestWithRemoveFromDictionary.isRemoveFromAllDossiers()) { var dictionaryEntriesToRemove = dictionaryManagementService.getAllEntriesInDossierTemplate(toTypeId(redactionLogEntry.getType(), dossierTemplateId), - redactionLogEntry.getValue()); + redactionLogEntry.getValue(), DictionaryEntryType.ENTRY); dictionaryEntriesToRemove.forEach(entry -> { typeIdsOfModifiedDictionaries.add(entry.getTypeId()); removeFromDictionary(entry.getTypeId(), entry.getValue(), dossierId, fileId, DictionaryEntryType.ENTRY); @@ -212,9 +212,7 @@ public class ManualRedactionDictionaryUpdateHandler { public void revertAddToDictionary(String value, DictionaryEntryType dictionaryEntryType, String fileId, String dossierId, Set typeIdsOfModifiedDictionaries) { - typeIdsOfModifiedDictionaries.forEach(typeId -> { - removeFromDictionary(typeId, value, dossierId, fileId, dictionaryEntryType); - }); + typeIdsOfModifiedDictionaries.forEach(typeId -> removeFromDictionary(typeId, value, dossierId, fileId, dictionaryEntryType)); } -- 2.47.2 From d40ef631168f10241997129b340fd89b81954978 Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Wed, 30 Aug 2023 15:46:49 +0200 Subject: [PATCH 7/7] RED-7317: Endpoint to change entity types of dict-based annotations * fix tests --- .../ManualRedactionDictionaryUpdateHandler.java | 6 +++--- .../peristence/v1/server/integration/tests/FileTest.java | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) 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 4c07842f9..684ff1a8d 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 @@ -111,14 +111,14 @@ public class ManualRedactionDictionaryUpdateHandler { Set typeIdsOfModifiedDictionaries = new HashSet<>(); if (manualRequestWithRemoveFromDictionary.isRemoveFromAllDossiers()) { var dictionaryEntriesToRemove = dictionaryManagementService.getAllEntriesInDossierTemplate(toTypeId(redactionLogEntry.getType(), dossierTemplateId), - redactionLogEntry.getValue(), DictionaryEntryType.ENTRY); + redactionLogEntry.getValue(), getDictionaryEntryType(redactionLogEntry)); dictionaryEntriesToRemove.forEach(entry -> { typeIdsOfModifiedDictionaries.add(entry.getTypeId()); - removeFromDictionary(entry.getTypeId(), entry.getValue(), dossierId, fileId, DictionaryEntryType.ENTRY); + removeFromDictionary(entry.getTypeId(), entry.getValue(), dossierId, fileId, getDictionaryEntryType(redactionLogEntry)); }); } else { typeIdsOfModifiedDictionaries.add(toTypeId(redactionLogEntry.getType(), dossierTemplateId, dossierId)); - removeFromDictionary(toTypeId(redactionLogEntry.getType(), dossierTemplateId, dossierId), redactionLogEntry.getValue(), dossierId, fileId, DictionaryEntryType.ENTRY); + removeFromDictionary(toTypeId(redactionLogEntry.getType(), dossierTemplateId, dossierId), redactionLogEntry.getValue(), dossierId, fileId, getDictionaryEntryType(redactionLogEntry)); } // This is needed to remove resizeRedactions with addToDictionary. 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 fa626540e..3a35e3652 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 @@ -52,6 +52,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp 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.dossier.file.ProcessingStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; +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.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; @@ -371,6 +372,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest { .reason("1") .value("test") .legalBasis("1") + .dictionaryEntryType(DictionaryEntryType.ENTRY) .build(); manualRedactionClient.addRedactionBulk(dossierId, fileId, Set.of(addRedactionRequest)); @@ -440,6 +442,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest { .reason("1") .value("test") .legalBasis("1") + .dictionaryEntryType(DictionaryEntryType.ENTRY) .build())).iterator().next(); var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); -- 2.47.2