From c9389e04fa9108ebc33011ffe19fc2d5a8dc5711 Mon Sep 17 00:00:00 2001 From: corinaolariu Date: Fri, 12 Jul 2024 15:59:22 +0300 Subject: [PATCH] RED-9474 - Revert only local manual changes for an annotation - rework the undo logic. Introduced new flag includeOnlyLocal to filter out the local changes. Now all manual changes will be reverted for the annotations provided. - unit tests added --- .../controller/ManualRedactionController.java | 5 +- .../resource/ManualRedactionResource.java | 5 +- .../model/ManualChangesQueryOptions.java | 8 +- .../service/EntityLogMongoWrapperService.java | 2 +- .../ManualRedactionProviderService.java | 23 +- .../ManualRedactionUndoService.java | 346 +++++++----------- .../AddRedactionPersistenceService.java | 9 +- .../ForceRedactionPersistenceService.java | 5 +- .../LegalBasisChangePersistenceService.java | 5 +- .../RecategorizationPersistenceService.java | 5 +- .../RemoveRedactionPersistenceService.java | 5 +- .../ResizeRedactionPersistenceService.java | 5 +- .../ForceRedactionRepository.java | 14 + .../LegalBasisChangeRepository.java | 13 + .../ManualRedactionRepository.java | 15 + .../RecategorizationRepository.java | 17 + .../RemoveRedactionRepository.java | 15 + .../ResizeRedactionRepository.java | 17 + .../tests/ManualRedactionTest.java | 131 ++++++- 19 files changed, 394 insertions(+), 251 deletions(-) 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 0bd75f712..80d969d62 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 @@ -71,12 +71,13 @@ public class ManualRedactionController implements ManualRedactionResource { public void undo(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody Set annotationIds, - @RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) { + @RequestParam(value = "includeOnlyUnprocessed", required = false, defaultValue = FALSE) boolean includeOnlyUnprocessed, + @RequestParam(value = "includeOnlyLocal", required = false, defaultValue = FALSE) boolean includeOnlyLocal) { accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId); accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsApprover(dossierId); - manualRedactionUndoService.undo(dossierId, fileId, annotationIds, includeUnprocessed); + manualRedactionUndoService.undo(dossierId, fileId, annotationIds, includeOnlyUnprocessed, includeOnlyLocal); } 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 a6163254c..cad373e9f 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 @@ -1,6 +1,5 @@ package com.iqser.red.service.persistence.service.v1.api.external.resource; -import java.util.List; import java.util.Set; import org.springframework.http.HttpStatus; @@ -15,7 +14,6 @@ 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.AnnotationComments; -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.ManualRedactionResponse; 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; @@ -57,7 +55,8 @@ public interface ManualRedactionResource { void undo(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody Set annotationIds, - @RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed); + @RequestParam(value = "includeOnlyUnprocessed", required = false, defaultValue = FALSE) boolean includeOnlyUnprocessed, + @RequestParam(value = "includeOnlyLocal", required = false, defaultValue = FALSE) boolean includeOnlyLocal); @ResponseStatus(value = HttpStatus.OK) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/ManualChangesQueryOptions.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/ManualChangesQueryOptions.java index db8c91ec1..efc747575 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/ManualChangesQueryOptions.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/ManualChangesQueryOptions.java @@ -5,7 +5,6 @@ import java.util.List; import java.util.Set; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.BaseAnnotation; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRedactionEntry; import lombok.Builder; import lombok.Getter; @@ -23,6 +22,8 @@ public class ManualChangesQueryOptions { private boolean includeDeletions = false; @Builder.Default private Set> excludedClasses = Collections.emptySet(); + @Builder.Default + private List annotationIds = Collections.emptyList(); public static ManualChangesQueryOptions allWithoutDeleted() { @@ -42,6 +43,11 @@ public class ManualChangesQueryOptions { return ManualChangesQueryOptions.builder().includeDeletions(false).includeDictChanges(true).includeOnlyUnprocessed(true).build(); } + public static ManualChangesQueryOptions unprocessedOnlyForIds(List annotationIds) { + + return ManualChangesQueryOptions.builder().includeDeletions(false).includeDictChanges(true).includeOnlyUnprocessed(true).annotationIds(annotationIds).build(); + } + public static ManualChangesQueryOptions localChangesOnly() { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMongoWrapperService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMongoWrapperService.java index 9814197cd..15dd91688 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMongoWrapperService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMongoWrapperService.java @@ -36,7 +36,7 @@ public class EntityLogMongoWrapperService { List entityLogEntries = entityLogMongoService.findEntityLogEntriesByIds(dossierId, fileId, ids); if (includeUnprocessed) { DossierEntity dossier = dossierService.getDossierById(dossierId); - ManualRedactions unprocessedManualRedactions = manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.unprocessedOnly(), ids); + ManualRedactions unprocessedManualRedactions = manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.unprocessedOnlyForIds(ids)); entityLogEntries = entityLogMergeService.mergeEntityLogEntries(unprocessedManualRedactions, entityLogEntries.stream().map(EntityLogEntry::getId).toList(), dossier, fileId); } return entityLogEntries; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/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 index 0bdabee5b..8f8a851db 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/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 @@ -4,9 +4,7 @@ import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicC import java.util.Collections; import java.util.HashSet; -import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.stereotype.Service; @@ -49,11 +47,11 @@ public class ManualRedactionProviderService { private final ResizeRedactionPersistenceService resizeRedactionPersistenceService; + public void convertUnprocessedAddToDictionariesToLocalChanges(String fileId) { - public void convertUnprocessedAddToDictionariesToLocalChanges(String fileId){ var unprocessedManualAdds = addRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, ManualChangesQueryOptions.unprocessedOnly()); - for (var unprocessedManualAdd : unprocessedManualAdds){ - if (unprocessedManualAdd.isAddToDictionary() || unprocessedManualAdd.isAddToAllDossiers()){ + for (var unprocessedManualAdd : unprocessedManualAdds) { + if (unprocessedManualAdd.isAddToDictionary() || unprocessedManualAdd.isAddToAllDossiers()) { unprocessedManualAdd.setAddToDictionary(false); unprocessedManualAdd.setAddToAllDossiers(false); unprocessedManualAdd.setLegalBasis(""); @@ -65,12 +63,6 @@ public class ManualRedactionProviderService { @Transactional public ManualRedactions getManualRedactions(String fileId, ManualChangesQueryOptions options) { - return getManualRedactions(fileId, options, Collections.emptyList()); - } - - - @Transactional - public ManualRedactions getManualRedactions(String fileId, ManualChangesQueryOptions options, List annotationIds) { Set entriesToAdd; Set removals; @@ -121,15 +113,6 @@ public class ManualRedactionProviderService { legalBasisChanges = Collections.emptySet(); } - if(!annotationIds.isEmpty()){ - return new ManualRedactions(removals.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet()), - entriesToAdd.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet()), - forceRedactions.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet()), - recategorizations.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet()), - legalBasisChanges.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet()), - resizeRedactions.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet())); - } - return new ManualRedactions(removals, entriesToAdd, forceRedactions, recategorizations, legalBasisChanges, resizeRedactions); } 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 c46938628..40c4cf1f9 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 @@ -19,6 +19,7 @@ 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.ManualRecategorizationEntity; 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.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions; import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; @@ -72,31 +73,56 @@ public class ManualRedactionUndoService { @Transactional - public void undo(String dossierId, String fileId, Set annotationIds, boolean includeUnprocessed) { + public void undo(String dossierId, String fileId, Set annotationIds, boolean includeOnlyUnprocessed, boolean includeOnlyLocal) { - // undo the latest manual redaction for each annotationId - ManualRedactions manualRedactions = getManualRedactions(fileId); + // undo the manual redaction for each annotationId + ManualRedactions manualRedactions = getManualRedactions(fileId, includeOnlyUnprocessed, includeOnlyLocal, new ArrayList<>(annotationIds)); - Map manualRedactionWrappers = getLatestManualRedactionsForAnnotationIds(manualRedactions, annotationIds); + Map> manualRedactionWrappers = groupAndSortManualRedactionsForAnnotationIds(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, includeUnprocessed); - undoLegalBasisChange(dossierId, fileId, manualRedactionWrappers); - undoResize(dossierId, fileId, manualRedactionWrappers); + for (String annotationId : manualRedactionWrappers.keySet()) { + manualRedactionWrappers.get(annotationId) + .stream() + .forEach(manualChange -> { + if (manualChange.getItem() instanceof ManualRedactionEntry) { + undoManualRedactionEntry(dossierId, fileId, annotationId); + } else if (manualChange.getItem() instanceof IdRemoval) { + undoIdRemoval(dossierId, fileId, annotationId); + } else if (manualChange.getItem() instanceof ManualResizeRedaction) { + undoResizeEntry(dossierId, fileId, annotationId); + } else if (manualChange.getItem() instanceof ManualLegalBasisChange) { + undoLegalBasisChangeEntry(dossierId, fileId, annotationId); + } else if (manualChange.getItem() instanceof ManualRecategorization) { + undoRecategorizationEntry(dossierId, fileId, annotationId, includeOnlyUnprocessed); + } else if (manualChange.getItem() instanceof ManualForceRedaction) { + undoForceRedactionEntry(dossierId, fileId, annotationId); + } + }); + } + reprocess(dossierId, fileId); fileStatusPersistenceService.setLastManualChangeDate(fileId, OffsetDateTime.now()); } - private ManualRedactions getManualRedactions(String fileId) { + private ManualRedactions getManualRedactions(String fileId, boolean includeOnlyUnprocessed, boolean includeOnlyLocal, List annotationIds) { - return manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.allWithoutDeleted()); + var fileStatus = fileStatusService.getStatus(fileId); + if (fileStatus.isExcludedFromAutomaticAnalysis() && !includeOnlyUnprocessed) { // analysis is disabled, only unprocessed changes can be reverted + throw new BadRequestException("Only unprocessed manual redactions can be reverted. includeOnlyUnprocessed must be set to true"); + } + + ManualChangesQueryOptions options = ManualChangesQueryOptions.builder() + .includeDeletions(false) + .includeDictChanges(!includeOnlyLocal) + .includeOnlyUnprocessed(includeOnlyUnprocessed) + .annotationIds(annotationIds) + .build(); + return manualRedactionProviderService.getManualRedactions(fileId, options); } @@ -106,236 +132,112 @@ public class ManualRedactionUndoService { } - private void undoResize(String dossierId, String fileId, Map manualRedactionWrappers) { - - List manualResizeRedactions = manualRedactionWrappers.values() - .stream() - .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualResizeRedaction) - .map(ManualRedactionWrapperModel::getId) - .toList(); - if (!manualResizeRedactions.isEmpty()) { - 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 deleteResizeRedaction(String dossierId, String fileId, List annotationIds) { + private void undoResizeEntry(String dossierId, String fileId, String annotationId) { OffsetDateTime now = OffsetDateTime.now(); - for (var annotationId : annotationIds) { - resizeRedactionPersistenceService.softDelete(fileId, annotationId, now); - } + resizeRedactionPersistenceService.softDelete(fileId, annotationId, now); + 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) { + private void undoLegalBasisChangeEntry(String dossierId, String fileId, String annotationId) { - List manualLegalBasisChanges = manualRedactionWrappers.values() - .stream() - .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualLegalBasisChange) - .map(ManualRedactionWrapperModel::getId) - .toList(); - if (!manualLegalBasisChanges.isEmpty()) { - - 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())); - } + legalBasisChangePersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); + 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 deleteLegalBasisChange(String dossierId, String fileId, List annotationIds) { + private void undoRecategorizationEntry(String dossierId, String fileId, String annotationId, boolean includeUnprocessed) { - for (var annotationId : annotationIds) { - legalBasisChangePersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - } - - } - - - private void undoRecategorization(String dossierId, String fileId, Map manualRedactionWrappers, boolean includeUnprocessed) { - - List manualRecategorizations = manualRedactionWrappers.values() - .stream() - .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualRecategorization) - .map(ManualRedactionWrapperModel::getId) - .toList(); - if (!manualRecategorizations.isEmpty()) { - - deleteRecategorization(dossierId, fileId, manualRecategorizations, includeUnprocessed); - manualRecategorizations.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(fileId) - .category(AuditCategory.DOCUMENT.name()) - .message("Undo of manual recategorization was done.") - .details(Map.of(DOSSIER_ID, - dossierId, - FILE_ID, - fileId, - ANNOTATION_ID, - annotationId)) - .build())); - } - } - - - private void deleteRecategorization(String dossierId, String fileId, List annotationIds, boolean includeUnprocessed) { - - dossierPersistenceService.getAndValidateDossier(dossierId); EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId, includeUnprocessed); - for (var annotationId : annotationIds) { - ManualRecategorizationEntity recategorizationEntity = recategorizationPersistenceService.findRecategorization(fileId, annotationId); - String originalValue = getEntityLogEntry(entityLog, annotationId).getValue(); - manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, recategorizationEntity.getTypeIdsOfDictionariesWithDelete()); - manualRedactionDictionaryUpdateHandler.revertAddToDictionary(originalValue, - DictionaryEntryType.ENTRY, - fileId, - dossierId, - recategorizationEntity.getTypeIdsOfDictionariesWithAdd()); - recategorizationEntity.setTypeIdsOfDictionariesWithAdd(Collections.emptySet()); - recategorizationEntity.setTypeIdsOfDictionariesWithDelete(Collections.emptySet()); - recategorizationEntity.setSoftDeletedTime(OffsetDateTime.now()); - recategorizationPersistenceService.saveAndFlush(recategorizationEntity); - } + ManualRecategorizationEntity recategorizationEntity = recategorizationPersistenceService.findRecategorization(fileId, annotationId); + String originalValue = getEntityLogEntry(entityLog, annotationId).getValue(); + manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, recategorizationEntity.getTypeIdsOfDictionariesWithDelete()); + manualRedactionDictionaryUpdateHandler.revertAddToDictionary(originalValue, + DictionaryEntryType.ENTRY, + fileId, + dossierId, + recategorizationEntity.getTypeIdsOfDictionariesWithAdd()); + recategorizationEntity.setTypeIdsOfDictionariesWithAdd(Collections.emptySet()); + recategorizationEntity.setTypeIdsOfDictionariesWithDelete(Collections.emptySet()); + recategorizationEntity.setSoftDeletedTime(OffsetDateTime.now()); + recategorizationPersistenceService.saveAndFlush(recategorizationEntity); + auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(fileId) + .category(AuditCategory.DOCUMENT.name()) + .message("Undo of manual 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) - .toList(); - if (!manualForceRedactions.isEmpty()) { - - 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 deleteForceRedaction(String dossierId, String fileId, List annotationIds) { + private void undoForceRedactionEntry(String dossierId, String fileId, String annotationId) { var now = OffsetDateTime.now(); - - for (var annotationId : annotationIds) { - forceRedactionPersistenceService.softDelete(fileId, annotationId, now); - } + forceRedactionPersistenceService.softDelete(fileId, annotationId, now); + 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) { + private void undoIdRemoval(String dossierId, String fileId, String annotationId) { - List idRemovals = manualRedactionWrappers.values() - .stream() - .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof IdRemoval) - .map(ManualRedactionWrapperModel::getId) - .toList(); - if (!idRemovals.isEmpty()) { - 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 deleteRemoveRedaction(String dossierId, String fileId, List annotationIds) { - - dossierPersistenceService.getAndValidateDossier(dossierId); EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId, true); - for (String annotationId : annotationIds) { + IdRemovalEntity removeRedaction = removeRedactionPersistenceService.findRemoveRedaction(fileId, annotationId); + String originalValue = getEntityLogEntry(entityLog, annotationId).getValue(); + boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, removeRedaction); + removeRedactionPersistenceService.updateModifiedDictionaries(fileId, annotationId, dictionaryChanged, Collections.emptySet()); + removeRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - IdRemovalEntity removeRedaction = removeRedactionPersistenceService.findRemoveRedaction(fileId, annotationId); - String originalValue = getEntityLogEntry(entityLog, annotationId).getValue(); - boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, removeRedaction); - removeRedactionPersistenceService.updateModifiedDictionaries(fileId, annotationId, dictionaryChanged, Collections.emptySet()); - removeRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - } + 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) { + private void undoManualRedactionEntry(String dossierId, String fileId, String annotationId) { - List manualRedactionEntries = manualRedactionWrappers.values() - .stream() - .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualRedactionEntry) - .map(ManualRedactionWrapperModel::getId) - .toList(); - if (!manualRedactionEntries.isEmpty()) { - 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())); - } - } + ManualRedactionEntryEntity addRedaction = addRedactionPersistenceService.findAddRedaction(fileId, annotationId); + boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertAddToDictionary(fileId, dossierId, addRedaction); + addRedactionPersistenceService.updateModifiedDictionaries(fileId, annotationId, dictionaryChanged, null); + addRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - 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.updateModifiedDictionaries(fileId, annotationId, dictionaryChanged, null); - addRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - } + 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()); } @@ -350,13 +252,13 @@ public class ManualRedactionUndoService { } - private Map getLatestManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set annotationIds) { + private Map> groupAndSortManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set annotationIds) { - Map result = new HashMap<>(); + Map> result = new HashMap<>(); annotationIds.forEach(annotationId -> { - var last = getLatestManualRedactionForAnnotationId(manualRedactions, annotationId); - if (last != null) { - result.put(annotationId, last); + var manualRedactionsForId = getLatestManualRedactionForAnnotationId(manualRedactions, annotationId); + if (manualRedactionsForId != null) { + result.put(annotationId, manualRedactionsForId); } }); @@ -364,7 +266,21 @@ public class ManualRedactionUndoService { } - private ManualRedactionWrapperModel getLatestManualRedactionForAnnotationId(ManualRedactions manualRedactions, String annotationId) { + 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.get(0)); + } + }); + + return result; + } + + + private List getLatestManualRedactionForAnnotationId(ManualRedactions manualRedactions, String annotationId) { final List manualRedactionWrappers = new ArrayList<>(); @@ -402,7 +318,7 @@ public class ManualRedactionUndoService { .sorted(Comparator.comparing(ManualRedactionWrapperModel::getDate, Comparator.nullsLast(Comparator.reverseOrder()))) .toList(); - return sortedManualRedactionWrappers.isEmpty() ? null : sortedManualRedactionWrappers.get(0); + return sortedManualRedactionWrappers.isEmpty() ? null : sortedManualRedactionWrappers; } } 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 96618f6a0..522cce0d6 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 @@ -83,7 +83,14 @@ public class AddRedactionPersistenceService { @Transactional public List findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) { - return manualRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges()); + if (options.getAnnotationIds().isEmpty()) { + return manualRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges()); + } + return manualRedactionRepository.findByFileIdAndOptionsAndAnnotationIds(fileId, + options.isIncludeDeletions(), + options.isIncludeOnlyUnprocessed(), + options.isIncludeDictChanges(), + options.getAnnotationIds()); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java index 0f24e1099..ebe5186c9 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java @@ -40,7 +40,10 @@ public class ForceRedactionPersistenceService { public List findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) { - return forceRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed()); + if (options.getAnnotationIds().isEmpty()) { + return forceRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed()); + } + return forceRedactionRepository.findByFileIdAndOptionsAndAnnotationIds(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.getAnnotationIds()); } public int softDeleteByFileIds(List fileIds, OffsetDateTime softDeletionTime) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java index 520c15a27..80dbb6188 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java @@ -81,7 +81,10 @@ public class LegalBasisChangePersistenceService { public List findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) { - return legalBasisChangeRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed()); + if (options.getAnnotationIds().isEmpty()) { + return legalBasisChangeRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed()); + } + return legalBasisChangeRepository.findByFileIdAndOptionsAndAnnotationIds(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.getAnnotationIds()); } public int softDeleteByFileIds(List fileIds, OffsetDateTime softDeletionTime) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java index 6b5148f7a..7da941ec7 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java @@ -89,7 +89,10 @@ public class RecategorizationPersistenceService { public List findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) { - return recategorizationRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges()); + if (options.getAnnotationIds().isEmpty()) { + return recategorizationRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges()); + } + return recategorizationRepository.findByFileIdAndOptionsAndAnnotationIds(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges(), options.getAnnotationIds()); } public int softDeleteByFileIds(List fileIds, OffsetDateTime softDeletionTime) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java index a8e9f2c4f..1fc3e29f1 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java @@ -49,7 +49,10 @@ public class RemoveRedactionPersistenceService { public List findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) { - return removeRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges()); + if (options.getAnnotationIds().isEmpty()) { + return removeRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges()); + } + return removeRedactionRepository.findByFileIdAndOptionsAndAnnotationIds(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges(), options.getAnnotationIds()); } public int softDeleteByFileIds(List fileIds, OffsetDateTime softDeletionTime) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java index fb8cde786..b36fe25d8 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java @@ -101,7 +101,10 @@ public class ResizeRedactionPersistenceService { public List findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) { - return resizeRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges()); + if (options.getAnnotationIds().isEmpty()) { + return resizeRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges()); + } + return resizeRedactionRepository.findByFileIdAndOptionsAndAnnotationIds(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges(), options.getAnnotationIds()); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ForceRedactionRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ForceRedactionRepository.java index 9161b965d..dc6b2679a 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ForceRedactionRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ForceRedactionRepository.java @@ -48,6 +48,20 @@ public interface ForceRedactionRepository extends JpaRepository findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId, + @Param("includeDeletions") boolean includeDeletions, + @Param("unprocessed") boolean unprocessed, + @Param("annotationIds") List annotationIds); + + @Modifying @Query("update ManualForceRedactionEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null") int softDeleteByFileIds(@Param("fileIds") List fileIds, @Param("softDeletedTime") OffsetDateTime softDeletedTime); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/LegalBasisChangeRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/LegalBasisChangeRepository.java index 2d2e8d9a5..c8fb46c06 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/LegalBasisChangeRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/LegalBasisChangeRepository.java @@ -47,6 +47,19 @@ public interface LegalBasisChangeRepository extends JpaRepository findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId, + @Param("includeDeletions") boolean includeDeletions, + @Param("unprocessed") boolean unprocessed, + @Param("annotationIds") List annotationIds); + @Modifying @Query("update ManualLegalBasisChangeEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null") diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ManualRedactionRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ManualRedactionRepository.java index 63f166de7..dd1725037 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ManualRedactionRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ManualRedactionRepository.java @@ -51,6 +51,21 @@ public interface ManualRedactionRepository extends JpaRepository findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId, + @Param("includeDeletions") boolean includeDeletions, + @Param("unprocessed") boolean unprocessed, + @Param("includeDictChanges") boolean includeDictChanges, + @Param("annotationIds") List annotationIds); + @Modifying @Query("update ManualRedactionEntryEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null") int softDeleteByFileIds(@Param("fileIds") List fileIds, diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RecategorizationRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RecategorizationRepository.java index 334453178..2cffa0b3f 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RecategorizationRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RecategorizationRepository.java @@ -49,6 +49,23 @@ public interface RecategorizationRepository extends JpaRepository findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId, + @Param("includeDeletions") boolean includeDeletions, + @Param("unprocessed") boolean unprocessed, + @Param("includeDictChanges") boolean includeDictChanges, + @Param("annotationIds") List annotationIds); + + @Modifying @Query("update ManualRecategorizationEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null") int softDeleteByFileIds(@Param("fileIds") List fileIds, diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RemoveRedactionRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RemoveRedactionRepository.java index 186251d4e..652f747b0 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RemoveRedactionRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RemoveRedactionRepository.java @@ -49,6 +49,21 @@ public interface RemoveRedactionRepository extends JpaRepository findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId, + @Param("includeDeletions") boolean includeDeletions, + @Param("unprocessed") boolean unprocessed, + @Param("includeDictChanges") boolean includeDictChanges, + @Param("annotationIds") List annotationIds); + @Modifying @Query("update IdRemovalEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null") int softDeleteByFileIds(@Param("fileIds") List fileIds, diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ResizeRedactionRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ResizeRedactionRepository.java index 7b0394fa6..1af6e793d 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ResizeRedactionRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ResizeRedactionRepository.java @@ -57,6 +57,23 @@ public interface ResizeRedactionRepository extends JpaRepository findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId, + @Param("includeDeletions") boolean includeDeletions, + @Param("unprocessed") boolean unprocessed, + @Param("includeDictChanges") boolean includeDictChanges, + @Param("annotationIds") List annotationIds); + + @Modifying @Query("update ManualResizeRedactionEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null") int softDeleteByFileIds(@Param("fileIds") List fileIds, 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 d400580db..c42923419 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 @@ -366,7 +366,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary.getEntries()).isEmpty(); - manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of("AnnotationId"), false); + manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of("AnnotationId"), false, false); dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker", "Darth Vader"); @@ -1244,7 +1244,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary2.getEntries()).isEmpty(); - manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId), false); + manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId), false, false); dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader); @@ -1258,6 +1258,131 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { } + @Test + public void testManualRecategorizeAndUndoOnlyManualChanges() { + + 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.getId(), 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.getId()); + 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.getId()); + assertThat(dossierDictionary2.getEntries()).isEmpty(); + + var annotationId = "AnnotationId"; + var entityLog = new EntityLog(1, + 1, + List.of(EntityLogEntry.builder() + .id(annotationId) + .type(type.getType()) + .value(lukeSkywalker) + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .build()), + null, + 0, + 0, + 0, + 0); + fileManagementStorageService.saveEntityLog(dossier.getId(), file.getId(), entityLog); + + when(entityLogService.getEntityLog(any(), any(), anyBoolean())).thenReturn(entityLog); + + manualRedactionClient.recategorizeBulk(dossier.getId(), + file.getId(), + Set.of(RecategorizationRequestModel.builder() + .type(type2.getType()) + .annotationId(annotationId) + .addToDictionary(true) + .addToAllDossiers(true) + .legalBasis("") + .section("section") + .value(lukeSkywalker) + .build()), + false); + + dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); + assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(darthVader); + dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); + 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.getId()); + assertThat(dossierDictionary2.getEntries()).isEmpty(); + + // try to undo only local changes, but there are none for the requested annotationId + String errorMessage = assertThrows(FeignException.NotFound.class, + () -> manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId), false, true)).getMessage(); + assertTrue(errorMessage.contains("ManualRedaction with annotationIds [AnnotationId] could not be found")); + + dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); + assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(darthVader); + dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); + 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.getId()); + assertThat(dossierDictionary2.getEntries()).isEmpty(); + + var resizeRedactionRequestModel = ResizeRedactionRequestModel.builder() + .annotationId(annotationId) + .value(lukeSkywalker + " resized") + .updateDictionary(false) + .addToAllDossiers(false) + .positions(List.of(Rectangle.builder().page(1).height(1).width(2).topLeftX(1).topLeftY(1).build())) + .build(); + + ManualRedactionResponse response = manualRedactionClient.resizeRedactionBulk(dossier.getId(), file.getId(), Set.of(resizeRedactionRequestModel), false); + + var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true); + + assertEquals(allManualRedactions.getResizeRedactions().size(), 1); + assertEquals(allManualRedactions.getEntriesToAdd().size(), 1); + assertEquals(allManualRedactions.getRecategorizations().size(), 1); + var entryToResize = allManualRedactions.getResizeRedactions() + .stream() + .findFirst() + .get(); + var entryToAdd = allManualRedactions.getEntriesToAdd() + .stream() + .findFirst() + .get(); + assertFalse(entryToAdd.isAddToDictionary()); + assertFalse(entryToAdd.isAddToDossierDictionary()); + assertEquals(entryToAdd.getAnnotationId(), entryToResize.getAnnotationId()); + + manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId, entryToResize.getAnnotationId()), false, true); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true); + + assertEquals(allManualRedactions.getResizeRedactions().size(), 0); + assertEquals(allManualRedactions.getEntriesToAdd().size(), 0); + assertEquals(allManualRedactions.getRecategorizations().size(), 1); + } + + @Test public void testManualRecategorizeAndUndoDossierLevelOnly() { @@ -1330,7 +1455,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary2.getEntries()).containsExactlyInAnyOrder(lukeSkywalker); - manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId), false); + manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId), false, false); dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).isEmpty(); -- 2.47.2