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..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 @@ -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,93 +18,53 @@ 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.ManualRedactionService; +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; 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.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.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.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.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; +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; 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 DossierManagementService dossierManagementService; - private final AuditPersistenceService auditPersistenceService; - private final AccessControlService accessControlService; - - - - private ManualRedactionWrapper 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 ManualRedactionWrapper(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))); - - manualRedactions.getIdsToRemove() - .stream() - .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(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))); - - manualRedactions.getLegalBasisChanges() - .stream() - .filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId)) - .forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(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))); - - var sortedManualRedactionWrappers = manualRedactionWrappers.stream() - .sorted(Comparator.comparing(ManualRedactionWrapper::getDate, Comparator.nullsLast(Comparator.reverseOrder()))) - .collect(Collectors.toList()); - - return sortedManualRedactionWrappers.isEmpty() ? null : sortedManualRedactionWrappers.get(0); - } + 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 @@ -115,129 +73,8 @@ public class ManualRedactionController implements ManualRedactionResource { 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(ManualRedactionWrapper::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(ManualRedactionWrapper::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(ManualRedactionWrapper::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(ManualRedactionWrapper::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(ManualRedactionWrapper::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(ManualRedactionWrapper::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; } @@ -258,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(fileId, List.of(Long.valueOf(commentId))); + commentService.deleteComment(dossierId, fileId, List.of(Long.valueOf(commentId))); } @@ -271,17 +108,26 @@ public class ManualRedactionController implements ManualRedactionResource { } + @Override + @PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')") + public Comments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { + + return commentService.getComments(fileId); + } + + @Override @PreAuthorize("hasAuthority('" + ADD_COMMENT + "')") 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); - var response = manualRedactionService.addComment(fileId, + var response = commentService.addComment(dossierId, + fileId, annotationId, CommentRequest.builder().user(KeycloakSecurity.getUserId()).text(addCommentRequest.getText()).build()); @@ -301,41 +147,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 +194,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 +236,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 +267,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 +299,35 @@ 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 -> RecategorizationRequest.builder() + .annotationId(recategorizationRequest.getAnnotationId()) .user(KeycloakSecurity.getUserId()) .status(AnnotationStatus.APPROVED) - .typeId(toTypeId(imageRecategorizationRequest.getType(), dossier.getDossierTemplateId())) - .comment(imageRecategorizationRequest.getComment()) + .dossierTemplateTypeId(toTypeId(recategorizationRequest.getType(), dossier.getDossierTemplateId())) + .comment(recategorizationRequest.getComment()) + .dossierId(dossierId) + .addToDictionary(recategorizationRequest.isAddToDictionary()) + .addToAllDossiers(recategorizationRequest.isAddToAllDossiers()) + .dictionaryEntryType(DictionaryEntryType.ENTRY) .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 +338,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-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-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..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,15 +13,16 @@ 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.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.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; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -58,7 +59,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 +78,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 +87,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 +96,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 +105,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 +123,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); @@ -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-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/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/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/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/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/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 1f8d07ea5..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,12 +1,11 @@ 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; 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; @@ -16,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; @@ -53,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/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/ManualRedactionService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ManualRedactionService.java deleted file mode 100644 index 0fbde10e3..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ManualRedactionService.java +++ /dev/null @@ -1,761 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.service; - -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.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.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.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 -@RequiredArgsConstructor -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(); - - - @Transactional - public List addAddRedaction(String dossierId, String fileId, List addRedactionRequests) { - - var response = new ArrayList(); - - dossierPersistenceService.getAndValidateDossier(dossierId); - - // validate add to dossier template dictionaries - addRedactionRequests.forEach(request -> dictionaryManagementService.validateAddRemoveToDossierTemplateDictionary(request.getDossierTemplateTypeId(), - request.isAddToDictionary(), - request.isAddToAllDossiers())); - - boolean actionPerformed = false; - for (var addRedactionRequest : addRedactionRequests) { - if (addRedactionRequest.isAddToDictionary()) { - validateDictionary(addRedactionRequest); - } - - 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()); - - response.add(ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).build()); - actionPerformed = actionPerformed || addRedactionRequest.getStatus().equals(AnnotationStatus.APPROVED); - } - - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - - if (actionPerformed) { - reprocess(dossierId, fileId); - } - - return response; - } - - - private void validateDictionary(AddRedactionRequest addRedactionRequest) { - - 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()); - } - } - - - private void validatePositions(String fileId, AddRedactionRequest addRedactionRequest) { - - var numberOfPages = fileStatusService.getStatus(fileId).getNumberOfPages(); - addRedactionRequest.getPositions().stream().filter(p -> p.getPage() > numberOfPages).findAny().ifPresent(p -> new BadRequestException("Invalid page found in the request")); - } - - - private CommentEntity addComment(String fileId, String annotationId, String comment, String user) { - - return commentPersistenceService.insert(CommentEntity.builder() - .text(comment) - .fileId(fileId) - .annotationId(annotationId) - .user(user) - .date(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)) - .build()); - } - - - 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); - } - - - 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 { - 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()); - } - } - - - 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()); - } - } - - - 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 (var removeRedactionRequest : removeRedactionRequests) { - - if (manualAddRedactionsContains(manualRedactions, removeRedactionRequest.getAnnotationId()) && AnnotationStatus.APPROVED.equals(removeRedactionRequest.getStatus())) { - 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()); - } - } - - 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 handleRemoveFromDictionary(RedactionLog redactionLog, - DossierEntity dossier, - String fileId, - String annotationId, - AnnotationStatus status, - boolean removeFromDictionary, - boolean removeFromAllDossiers, - boolean revert) { - - if (status == AnnotationStatus.APPROVED) { - - 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); - } - return false; - } - - - 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; - } - - - 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) { - - var response = new ArrayList(); - dossierPersistenceService.getAndValidateDossier(dossierId); - var actionPerformed = false; - - for (var forceRedactionRequest : forceRedactionRequests) { - forceRedactionPersistenceService.insert(fileId, forceRedactionRequest); - - Long commentId = null; - if (forceRedactionRequest.getComment() != null) { - - commentId = addComment(fileId, forceRedactionRequest.getAnnotationId(), forceRedactionRequest.getComment(), forceRedactionRequest.getUser()).getId(); - } - actionPerformed = actionPerformed || forceRedactionRequest.getStatus().equals(AnnotationStatus.APPROVED); - response.add(ManualAddResponse.builder().annotationId(forceRedactionRequest.getAnnotationId()).commentId(commentId).build()); - } - - if (actionPerformed) { - 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 = null; - if (legalBasisChangeRequest.getComment() != null) { - - commentId = addComment(fileId, legalBasisChangeRequest.getAnnotationId(), legalBasisChangeRequest.getComment(), legalBasisChangeRequest.getUser()).getId(); - } - - response.add(ManualAddResponse.builder().annotationId(legalBasisChangeRequest.getAnnotationId()).commentId(commentId).build()); - } - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - - return response; - } - - - @Transactional - public List addImageRecategorization(String dossierId, String fileId, List imageRecategorizationRequests) { - - var response = new ArrayList(); - var actionPerformed = false; - dossierPersistenceService.getAndValidateDossier(dossierId); - - for (var imageRecategorizationRequest : imageRecategorizationRequests) { - recategorizationPersistenceService.insert(fileId, imageRecategorizationRequest); - - Long commentId = null; - if (imageRecategorizationRequest.getComment() != null) { - - commentId = addComment(fileId, - imageRecategorizationRequest.getAnnotationId(), - imageRecategorizationRequest.getComment(), - imageRecategorizationRequest.getUser()).getId(); - } - - actionPerformed = actionPerformed || imageRecategorizationRequest.getStatus().equals(AnnotationStatus.APPROVED); - - response.add(ManualAddResponse.builder().annotationId(imageRecategorizationRequest.getAnnotationId()).commentId(commentId).build()); - } - if (actionPerformed) { - reprocess(dossierId, fileId); - } - - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - - return response; - } - - - public CommentEntity addComment(String fileId, String annotationId, CommentRequest commentRequest) { - - var createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser()); - - fileStatusPersistenceService.updateHasComments(fileId, true); - - return createdComment; - } - - - @Transactional - public void deleteAddRedaction(String dossierId, String fileId, List annotationIds) { - - var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); - var actionPerformed = 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()); - addRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - } - - if (actionPerformed) { - reprocess(dossierId, fileId); - } - - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - } - - - @Transactional - public void deleteRemoveRedaction(String dossierId, String fileId, List annotationIds) { - - var dossier = dossierPersistenceService.getAndValidateDossier(dossierId); - var actionPerformed = false; - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId, true, true); - - for (var annotationId : annotationIds) { - - var removeRedaction = getRemoveRedaction(fileId, annotationId); - - var removedFromDictionary = handleRemoveFromDictionary(redactionLog, - dossier, - fileId, - annotationId, - removeRedaction.getStatus(), - removeRedaction.isRemoveFromDictionary(), - removeRedaction.isRemoveFromAllDossiers(), - true); - - actionPerformed = actionPerformed || removedFromDictionary; - removeRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - } - - if (actionPerformed) { - 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 deleteImageRecategorization(String dossierId, String fileId, List annotationIds) { - - var actionPerformed = false; - for (var annotationId : annotationIds) { - var imageRecategorization = getImageRecategorization(fileId, annotationId); - - recategorizationPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); - - actionPerformed = actionPerformed || !AnnotationStatus.REQUESTED.equals(imageRecategorization.getStatus()); - } - - if (actionPerformed) { - reprocess(dossierId, fileId); - } - analysisFlagsCalculationService.calculateFlags(dossierId, fileId); - } - - - private ManualImageRecategorizationEntity getImageRecategorization(String fileId, String annotationId) { - - return recategorizationPersistenceService.findRecategorization(fileId, annotationId); - } - - - @Transactional - public void deleteComment(String fileId, List commentIds) { - - for (var commentId : commentIds) { - commentPersistenceService.softDelete(commentId, OffsetDateTime.now()); - } - // update indicator - fileStatusPersistenceService.updateHasComments(fileId, commentPersistenceService.fileHasComments(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) { - - var response = new ArrayList(); - - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId, true, true); - - for (ResizeRedactionRequest resizeRedactionRequest : resizeRedactionRequests) { - - var resizeRedaction = resizeRedactionPersistenceService.insert(fileId, resizeRedactionRequest); - - if (resizeRedactionRequest.getComment() != null) { - var 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()))) { - 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); - } - - - @Transactional - public void updateProcessedDate(String fileId, ManualRedactions manualRedactions) { - - if (manualRedactions != null) { - - if (manualRedactions.getEntriesToAdd() != null) { - manualRedactions.getEntriesToAdd().forEach(e -> { - if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) { - addRedactionPersistenceService.markAsProcessed(e); - } - }); - } - if (manualRedactions.getIdsToRemove() != null) { - manualRedactions.getIdsToRemove().forEach(e -> { - if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) { - removeRedactionPersistenceService.markAsProcessed(e); - } - }); - } - if (manualRedactions.getForceRedactions() != null) { - manualRedactions.getForceRedactions().forEach(e -> { - if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) { - forceRedactionPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId()); - } - }); - } - if (manualRedactions.getImageRecategorization() != null) { - manualRedactions.getImageRecategorization().forEach(e -> { - if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) { - recategorizationPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId()); - } - }); - } - if (manualRedactions.getResizeRedactions() != null) { - manualRedactions.getResizeRedactions().forEach(e -> { - if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) { - resizeRedactionPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId()); - } - }); - } - } - } - -} 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 new file mode 100644 index 000000000..684ff1a8d --- /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,304 @@ +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.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.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; +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.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 { + + DictionaryManagementService dictionaryManagementService; + DictionaryPersistenceService dictionaryPersistenceService; + FileStatusPersistenceService fileStatusPersistenceService; + ResizeRedactionPersistenceService resizeRedactionPersistenceService; + DossierPersistenceService dossierPersistenceService; + StopwordService stopwordService; + + + public Set handleAddToDictionaryAndReturnModifiedTypeIds(String fileId, String value, ManualRequestWithAddToDictionary manualRequestWithAddToDictionary) { + + if (!manualRequestWithAddToDictionary.isAddToDictionary()) { + return Collections.emptySet(); + } + Set typeIdsOfModifiedDictionaries = new HashSet<>(); + if (manualRequestWithAddToDictionary.isAddToAllDossiers()) { + 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, manualRequestWithAddToDictionary.getDictionaryEntryType()); + 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(), + 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(), getDictionaryEntryType(redactionLogEntry)); + dictionaryEntriesToRemove.forEach(entry -> { + typeIdsOfModifiedDictionaries.add(entry.getTypeId()); + 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, getDictionaryEntryType(redactionLogEntry)); + } + + // 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.isAddToDictionary()) { + return false; + } + + 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 { + 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()); + } + } + + + 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/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 new file mode 100644 index 000000000..2318b92f5 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java @@ -0,0 +1,407 @@ +package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +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.exception.BadRequestException; +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.FileStatusService; +import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService; +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.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.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.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.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 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 { + + 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 + public List addAddRedaction(String dossierId, String fileId, List addRedactionRequests) { + + var response = new ArrayList(); + + dossierPersistenceService.getAndValidateDossier(dossierId); + + for (AddRedactionRequest addRedactionRequest : addRedactionRequests) { + 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, addRedactionRequest.getValue(), addRedactionRequest); + + addRedactionPersistenceService.updateStatus(fileId, + annotationId, + addRedactionRequest.getStatus(), + !typeIdsOfModifiedDictionaries.isEmpty(), + typeIdsOfModifiedDictionaries); + + Long commentId = commentService.addCommentAndGetId(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser()); + + response.add(ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).build()); + } + + analysisFlagsCalculationService.calculateFlags(dossierId, fileId); + + if (addRedactionRequests.stream().anyMatch(BaseManualRequest::isApproved)) { + reprocess(dossierId, fileId); + } + + return response; + } + + + public List addRemoveRedaction(String dossierId, String fileId, List removeRedactionRequests) { + + 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; + } + + 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; + } + + + @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 = 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; + } + + + private void validatePositions(String fileId, AddRedactionRequest addRedactionRequest) { + + var numberOfPages = fileStatusService.getStatus(fileId).getNumberOfPages(); + addRedactionRequest.getPositions().stream().filter(p -> p.getPage() > numberOfPages).findAny().ifPresent(p -> new BadRequestException("Invalid page found in the request")); + } + + + private void reprocess(String dossierId, String fileId) { + + fileStatusService.setStatusReprocessForManual(dossierId, fileId, true); + } + + + 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()); + } + } + + + 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 boolean manualAddRedactionsContains(ManualRedactions manualRedactions, String annotationId) { + + return manualRedactions.getEntriesToAdd().stream().anyMatch(m -> annotationId.equals(m.getAnnotationId())); + } + + + 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.")); + } + + + public ManualRedactions getManualRedactions(String fileId) { + + return manualRedactionProviderService.getManualRedactions(fileId); + } + + + @Transactional + public void updateProcessedDate(ManualRedactions manualRedactions) { + + if (manualRedactions != null) { + + if (manualRedactions.getEntriesToAdd() != null) { + manualRedactions.getEntriesToAdd().forEach(e -> { + if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) { + addRedactionPersistenceService.markAsProcessed(e); + } + }); + } + if (manualRedactions.getIdsToRemove() != null) { + manualRedactions.getIdsToRemove().forEach(e -> { + if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) { + removeRedactionPersistenceService.markAsProcessed(e); + } + }); + } + if (manualRedactions.getForceRedactions() != null) { + manualRedactions.getForceRedactions().forEach(e -> { + if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) { + forceRedactionPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId()); + } + }); + } + if (manualRedactions.getImageRecategorization() != null) { + manualRedactions.getImageRecategorization().forEach(e -> { + if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) { + recategorizationPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId()); + } + }); + } + if (manualRedactions.getResizeRedactions() != null) { + manualRedactions.getResizeRedactions().forEach(e -> { + if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) { + resizeRedactionPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId()); + } + }); + } + } + } + +} 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..67e23bd93 --- /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,380 @@ +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.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Collections; +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 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; +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.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 { + + 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 = 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 ManualRedactions getManualRedactions(String fileId) { + + return manualRedactionProviderService.getManualRedactions(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()) { + 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) { + + 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() + .stream() + .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualLegalBasisChange) + .map(ManualRedactionWrapperModel::getId) + .collect(Collectors.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())); + } + } + + + 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() + .stream() + .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualImageRecategorization) + .map(ManualRedactionWrapperModel::getId) + .collect(Collectors.toList()); + if (!manualImageRecategorizations.isEmpty()) { + + 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 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() + .stream() + .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualForceRedaction) + .map(ManualRedactionWrapperModel::getId) + .collect(Collectors.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) { + + 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() + .stream() + .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof IdRemoval) + .map(ManualRedactionWrapperModel::getId) + .collect(Collectors.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); + 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() + .stream() + .filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualRedactionEntry) + .map(ManualRedactionWrapperModel::getId) + .collect(Collectors.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())); + } + } + + + 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<>(); + 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-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 3c96b3032..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 @@ -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; @@ -13,7 +14,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,12 +27,13 @@ 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()); + manualImageRecategorization.setTypeId(recategorizationRequest.getDossierTemplateTypeId()); imageRecategorizationRepository.saveAndFlush(manualImageRecategorization); } @@ -43,6 +45,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 38dc7672a..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,550 +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; - processManualImageRecategorization(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 processManualImageRecategorization(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); - 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/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-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/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 2f2ebdb01..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 @@ -1,27 +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.dossiertemplate.type.DictionaryEntryType; -import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.*; -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; @@ -31,7 +11,59 @@ 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.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; +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 { @@ -98,7 +130,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(); @@ -325,31 +356,38 @@ 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(AddRedactionRequest.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") + .dictionaryEntryType(DictionaryEntryType.ENTRY) + .build(); + manualRedactionClient.addRedactionBulk(dossierId, fileId, Set.of(addRedactionRequest)); + manualRedactionClient.removeRedactionBulk(dossierId, fileId, - Set.of(RemoveRedactionRequest.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(ForceRedactionRequest.builder().annotationId("forceRedactionAnnotation").comment("comment").legalBasis("1").build())); - manualRedactionClient.legalBasisChangeBulk(dossierId, + 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(annotationId).comment("comment").type("new-type").build())); var loadedFile = fileClient.getFileStatus(dossierId, fileId); @@ -396,20 +434,19 @@ 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") .legalBasis("1") - .dictionaryEntryType(DictionaryEntryType.ENTRY) + .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(); @@ -433,7 +470,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); @@ -510,6 +546,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest { } + @Test public void testFile6034SetUnderReview() { @@ -537,17 +574,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); @@ -556,6 +591,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 da817ecf5..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 @@ -13,12 +13,14 @@ 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.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.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; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import feign.FeignException; @@ -105,12 +107,12 @@ 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(), 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 +133,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 +168,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 +203,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) @@ -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, @@ -254,11 +256,11 @@ 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(), - Set.of(RemoveRedactionRequest.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"); @@ -302,11 +304,11 @@ 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(), - 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); @@ -343,11 +345,11 @@ 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(), - 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 +377,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 +391,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) @@ -427,8 +429,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,11 +446,10 @@ 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 = 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) @@ -576,8 +576,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,11 +593,10 @@ 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 = ResizeRedactionRequest.builder() + var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder() .annotationId(addRedactions.get(0).getAnnotationId()) .comment("resized dossier redaction") .value("test redaction in dossier") @@ -676,7 +674,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 +688,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) @@ -727,8 +725,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,11 +742,10 @@ 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 = 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 +820,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 +834,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) @@ -875,8 +871,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,11 +888,10 @@ 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 = ResizeRedactionRequest.builder() + var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder() .annotationId(addRedactions.get(1).getAnnotationId()) .comment("resized dossier template redaction") .value("test redaction in dossier template") @@ -956,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()).isEmpty(); + + 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-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 3d7f37771..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 { +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/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/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/annotations/Comments.java similarity index 61% rename from 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 to persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comments.java index d5a5ab696..07bce8c08 100644 --- 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/annotations/Comments.java @@ -1,4 +1,7 @@ -package com.iqser.red.service.persistence.service.v1.api.shared.model.manual; +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; @@ -9,10 +12,8 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class ImageRecategorizationRequest { +public class Comments { - private String annotationId; - private String type; - private String comment; + Map> comments; } 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/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 new file mode 100644 index 000000000..d06ef8539 --- /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/ManualRequestWithAddToDictionary.java @@ -0,0 +1,24 @@ +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 ManualRequestWithAddToDictionary extends BaseManualRequest { + + 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/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 new file mode 100644 index 000000000..1a7e371a3 --- /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,51 @@ +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 ManualRequestWithAddToDictionary, ManualRequestWithRemoveFromDictionary { + + String annotationId; + String user; + AnnotationStatus status; + String dossierTemplateTypeId; + String dossierId; + String comment; + int page; + boolean addToDictionary; + boolean addToAllDossiers; + private DictionaryEntryType dictionaryEntryType; + + + @Override + public boolean isForceAddToDictionary() { + + return true; + } + + + @Override + public boolean isRemoveFromDictionary() { + + 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 eb94b5453..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 { +public class RemoveRedactionRequest implements ManualRequestWithRemoveFromDictionary { 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/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