diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMergeService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMergeService.java index bae486e92..3d0b6d270 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMergeService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogMergeService.java @@ -393,7 +393,7 @@ public class EntityLogMergeService { entityLogEntry.setState(EntryState.IGNORED); //special case, only for add local and remove only - if (entityLogEntry.getEngines().equals(Set.of(Engine.MANUAL))) { + if (entityLogEntry.getEngines().contains(Engine.MANUAL)) { entityLogEntry.setState(EntryState.REMOVED); change.setType(ChangeType.REMOVED); } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogMergeTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogMergeTest.java index 0cf5f79d6..5d447315a 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogMergeTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogMergeTest.java @@ -681,12 +681,7 @@ public class EntityLogMergeTest { String entryId = UUID.randomUUID().toString(); ManualRedactions manualRedactions = ManualRedactions.builder() - .idsToRemove(Set.of(IdRemoval.builder() - .annotationId(entryId) - .fileId("file") - .requestDate(OffsetDateTime.now()) - .user("user") - .build())) + .idsToRemove(Set.of(IdRemoval.builder().annotationId(entryId).fileId("file").requestDate(OffsetDateTime.now()).user("user").build())) .build(); var entityLog = new EntityLog(1, @@ -725,7 +720,8 @@ public class EntityLogMergeTest { .findFirst(); assertTrue(optionalEntityLogEntry.isPresent()); assertEquals(optionalEntityLogEntry.get().getChanges().size(), 1); - assertEquals(optionalEntityLogEntry.get().getChanges().get(0).getType(), ChangeType.IGNORED); + assertEquals(optionalEntityLogEntry.get().getChanges() + .get(0).getType(), ChangeType.IGNORED); } @@ -914,5 +910,164 @@ public class EntityLogMergeTest { .build(); } + + @Test + public void testRecategorizeWithoutCreatingOverlap() { + + String fileId = "fileId"; + String dossierId = "dossierId"; + String dossierTemplateId = "dossierTemplateId"; + + String entryId = UUID.randomUUID().toString(); + String dictId = UUID.randomUUID().toString(); + + ManualRedactionEntry add = provideManualAdd(entryId, "Sensitive information"); + add.setType("CBI_author"); + ManualRedactions manualRedactions = ManualRedactions.builder() + .entriesToAdd(Set.of(add)) + .recategorizations(Set.of(ManualRecategorization.builder() + .annotationId(entryId) + .fileId(fileId) + .legalBasis("New legal basis") + .type("PII") + .requestDate(OffsetDateTime.now()) + .basedOnDictAnnotationId(dictId) + .user("User") + .build())) + .build(); + + List positions = new ArrayList<>(); + positions.add(new Position(1, 1, 1, 1, 1)); + + EntityLogEntry existingEntry = EntityLogEntry.builder() + .id(dictId) + .type("CBI_author") + .value("Sensitive Information") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(true) + .positions(positions) + .legalBasis("Initial legal basis") + .build(); + + EntityLog entityLog = new EntityLog(1, 1, Lists.newArrayList(existingEntry), Collections.emptyList(), 0, 0, 0, 0); + + when(manualRedactionProviderService.getManualRedactions(any(), any())).thenReturn(manualRedactions); + when(fileStatusService.getStatus(fileId)).thenReturn(FileModel.builder().excluded(false).dossierStatusId(dossierTemplateId).id(fileId).build()); + when(fileManagementStorageService.getEntityLog(dossierId, fileId)).thenReturn(entityLog); + when(dossierService.getDossierById(dossierId)).thenReturn(DossierEntity.builder().dossierTemplateId(dossierTemplateId).build()); + when(dictionaryPersistenceService.getType(anyString())).thenReturn(TypeEntity.builder().isHint(false).build()); + when(fileStatusPersistenceService.getStatus(fileId)).thenReturn(FileEntity.builder().id(fileId).fileAttributes(Collections.emptyList()).build()); + when(fileStatusService.convertAttributes(any(), anyString())).thenReturn(Collections.emptyList()); + + EntityLog response = entityLogMergeService.mergeEntityLog(manualRedactions, entityLog, DossierEntity.builder().dossierTemplateId(dossierTemplateId).build()); + + assertNotNull(response, "The merged EntityLog should not be null."); + assertFalse(response.getEntityLogEntry().isEmpty(), "The merged EntityLog should contain entries."); + + var updatedEntryOpt = response.getEntityLogEntry() + .stream() + .filter(e -> e.getId().equals(entryId)) + .findFirst(); + + assertTrue(updatedEntryOpt.isPresent(), "The recategorized entry should be present in the EntityLog."); + + EntityLogEntry updatedEntry = updatedEntryOpt.get(); + + assertEquals("PII", updatedEntry.getType(), "The entry type should be updated to PII."); + + assertEquals("New legal basis", updatedEntry.getLegalBasis(), "The legal basis should be updated."); + + assertEquals(EntryState.APPLIED, updatedEntry.getState(), "The entry state should remain APPLIED."); + + assertEquals(1, + response.getEntityLogEntry() + .stream() + .filter(entityLogEntry -> !entityLogEntry.getState().equals(EntryState.REMOVED)) + .count(), + "There should be only one entry in the EntityLog after recategorization."); + + } + + + @Test + public void testForceRedactSkippedCBIAddressAndLocalRemoveWithoutCreatingDuplicate() { + + String fileId = "fileId"; + String dossierId = "dossierId"; + String dossierTemplateId = "dossierTemplateId"; + + String entryId = UUID.randomUUID().toString(); + String dictId = UUID.randomUUID().toString(); + + ManualRedactionEntry add = provideManualAdd(entryId, "123 Main St"); + add.setType("CBI_address"); + ManualRedactions manualRedactions = ManualRedactions.builder() + .entriesToAdd(Set.of(add)) + .forceRedactions(Set.of(ManualForceRedaction.builder() + .annotationId(entryId) + .fileId(fileId) + .legalBasis("Force") + .user("User") + .requestDate(OffsetDateTime.now()) + .basedOnDictAnnotationId(dictId) + .build())) + .idsToRemove(Set.of(IdRemoval.builder().annotationId(entryId).fileId(fileId).user("User").requestDate(OffsetDateTime.now()).build())) + .build(); + + List positions = new ArrayList<>(); + positions.add(new Position(1, 1, 1, 1, 1)); + + EntityLogEntry existingEntry = EntityLogEntry.builder() + .id(dictId) + .type("CBI_address") + .value("123 Main St") + .entryType(EntryType.ENTITY) + .state(EntryState.SKIPPED) + .dictionaryEntry(true) + .positions(positions) + .legalBasis("Initial legal basis") + .build(); + + EntityLog entityLog = new EntityLog(1, 1, Lists.newArrayList(existingEntry), Collections.emptyList(), 0, 0, 0, 0); + when(manualRedactionProviderService.getManualRedactions(any(), any())).thenReturn(manualRedactions); + when(fileStatusService.getStatus(fileId)).thenReturn(FileModel.builder().excluded(false).dossierStatusId(dossierTemplateId).id(fileId).build()); + when(fileManagementStorageService.getEntityLog(dossierId, fileId)).thenReturn(entityLog); + when(dossierService.getDossierById(dossierId)).thenReturn(DossierEntity.builder().dossierTemplateId(dossierTemplateId).build()); + when(dictionaryPersistenceService.getType(anyString())).thenReturn(TypeEntity.builder().isHint(false).build()); + when(fileStatusPersistenceService.getStatus(fileId)).thenReturn(FileEntity.builder().id(fileId).fileAttributes(Collections.emptyList()).build()); + when(fileStatusService.convertAttributes(any(), anyString())).thenReturn(Collections.emptyList()); + + EntityLog response = entityLogMergeService.mergeEntityLog(manualRedactions, entityLog, DossierEntity.builder().dossierTemplateId(dossierTemplateId).build()); + + assertNotNull(response, "The merged EntityLog should not be null."); + assertFalse(response.getEntityLogEntry().isEmpty(), "The merged EntityLog should contain entries."); + + List relatedEntries = response.getEntityLogEntry() + .stream() + .filter(e -> e.getId().equals(entryId)) + .toList(); + + assertEquals(1, relatedEntries.size(), "There should be only one entry for the entryId after force redaction and local removal."); + + EntityLogEntry updatedEntry = relatedEntries.get(0); + + assertEquals("CBI_address", updatedEntry.getType(), "The entry type should remain CBI_address after force redaction and local removal."); + + long skippedAnnotations = response.getEntityLogEntry() + .stream() + .filter(e -> e.getType().equals("manual") && e.getEntryType() == EntryType.AREA && e.getState() == EntryState.SKIPPED) + .count(); + + assertEquals(0, skippedAnnotations, "No additional skipped annotations (Cross Marks) should be present."); + + var nonRemovedEntries = response.getEntityLogEntry() + .stream() + .filter(e -> !e.getId().equals(entryId) && !e.getState().equals(EntryState.REMOVED)) + .toList(); + + assertEquals(1, nonRemovedEntries.size(), "There should be only one entry in the EntityLog after force and local remove."); + } + }