diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/SearchTermOccurrencesResponseReceiver.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/SearchTermOccurrencesResponseReceiver.java index dd2837135..33912b535 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/SearchTermOccurrencesResponseReceiver.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/SearchTermOccurrencesResponseReceiver.java @@ -1,6 +1,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service.queue; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -21,12 +22,16 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.iqser.red.service.persistence.management.v1.processor.model.websocket.AnalyseStatus; import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService; +import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.websocket.WebsocketService; import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; import com.iqser.red.service.persistence.service.v1.api.shared.model.BulkLocalResponse; +import com.iqser.red.service.persistence.service.v1.api.shared.model.FoundTerm; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAnnotationResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle; @@ -56,6 +61,7 @@ public class SearchTermOccurrencesResponseReceiver { AuditPersistenceService auditPersistenceService; FileStatusPersistenceService fileStatusPersistenceService; WebsocketService webSocketService; + EntityLogService entityLogService; @RabbitHandler @@ -85,17 +91,20 @@ public class SearchTermOccurrencesResponseReceiver { var dossier = dossierManagementService.getDossierById(response.getDossierId(), false, false); + var entityLog = entityLogService.getEntityLog(response.getDossierId(), response.getFileId(), new ArrayList<>(), false); + Set addRedactionRequests = response.getFoundTerms() .stream() .map(term -> AddRedactionRequestModel.builder() - .type(response.getType()) - .value(term.value()) - .reason(response.getReason()) - .legalBasis(response.getLegalBasis()) - .positions(convertPositions(term.positions())) - .section(response.getSection()) - .comment(response.getComment() == null ? null : new AddCommentRequestModel(response.getComment())) - .build()) + .type(response.getType()) + .value(term.value()) + .reason(response.getReason()) + .legalBasis(response.getLegalBasis()) + .positions(convertPositions(term.positions())) + .section(response.getSection()) + .comment(response.getComment() == null ? null : new AddCommentRequestModel(response.getComment())) + .sourceId(getAnnotationId(entityLog, term)) + .build()) .collect(Collectors.toSet()); log.info("Received manual redaction requests for file {} in dossier {} after term search", response.getFileId(), dossier.getId()); @@ -125,6 +134,21 @@ public class SearchTermOccurrencesResponseReceiver { } + private String getAnnotationId(EntityLog entityLog, FoundTerm term) { + + var optionalEntry = entityLog.getEntityLogEntry() + .stream() + .filter(entry -> entry.getValue().equals(term.value()) + && entry.getPositions().equals(term.positions()) + && (entry.isDictionaryEntry() || entry.isDossierDictionaryEntry())) + .findFirst(); + if (optionalEntry.isPresent()) { + return optionalEntry.get().getId(); + } + return null; + } + + private List convertPositions(List positions) { return positions.stream() 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 094b1c43f..2d2936f9f 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 @@ -4174,4 +4174,152 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { } } } + + @Test + public void testSingleForceAndBulkForceOnDictEntryAutomaticAnalysisOff() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + + fileStatusPersistenceService.toggleAutomaticAnalysis(file.getId(), true); + whenGetEntityLogInvocation(); + + var type1 = typeProvider.testAndProvideType(dossierTemplate, dossier, "test1", false, 70); + + List entityLogEntries = new ArrayList<>(); + String legal2 = "Legal 2"; + String legal3 = "Legal 3"; + String darthVader = "Darth Vader"; + List position1 = List.of(new Position(56.8f, 528.9f, 120.96f, 12.64f, 1)); + List position2 = List.of(new Position(56.8f, 501.3f, 120.96f, 12.64f, 1)); + List position3 = List.of(new Position(56.8f, 473.7f, 120.96f, 12.64f, 1)); + List position4 = List.of(new Position(56.8f, 446.1f, 120.96f, 12.64f, 1)); + entityLogEntries.add(EntityLogEntry.builder() + .id("AnnotationId1") + .type(type1.getType()) + .value(darthVader) + .entryType(EntryType.ENTITY) + .state(EntryState.SKIPPED) + .section("section") + .legalBasis("Legal 1") + .engines(Set.of(Engine.DOSSIER_DICTIONARY)) + .dictionaryEntry(true) + .dossierDictionaryEntry(true) + .positions(position1) + .build()); + entityLogEntries.add(EntityLogEntry.builder() + .id("AnnotationId2") + .type(type1.getType()) + .value(darthVader) + .entryType(EntryType.ENTITY) + .state(EntryState.SKIPPED) + .section("section") + .legalBasis("Legal 1") + .engines(Set.of(Engine.DOSSIER_DICTIONARY)) + .dictionaryEntry(true) + .dossierDictionaryEntry(true) + .positions(position2) + .build()); + entityLogEntries.add(EntityLogEntry.builder() + .id("AnnotationId3") + .type(type1.getType()) + .value(darthVader) + .entryType(EntryType.ENTITY) + .state(EntryState.SKIPPED) + .section("section") + .legalBasis("Legal 1") + .engines(Set.of(Engine.DOSSIER_DICTIONARY)) + .dictionaryEntry(true) + .dossierDictionaryEntry(true) + .positions(position3) + .build()); + entityLogEntries.add(EntityLogEntry.builder() + .id("AnnotationId4") + .type(type1.getType()) + .value(darthVader) + .entryType(EntryType.ENTITY) + .state(EntryState.SKIPPED) + .section("section") + .legalBasis("Legal 1") + .engines(Set.of(Engine.DOSSIER_DICTIONARY)) + .dictionaryEntry(true) + .dossierDictionaryEntry(true) + .positions(position4) + .build()); +// } + var entityLog = new EntityLog(1, 1, entityLogEntries, null, 0, 0, 0, 0); + fileManagementStorageService.saveEntityLog(dossier.getId(), file.getId(), entityLog); + + // single force + manualRedactionClient.forceRedactionBulk(dossier.getId(), file.getId(), Set.of(ForceRedactionRequestModel.builder() + .annotationId("AnnotationId1") + .legalBasis(legal2) + .build())); + + var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, false); + + assertEquals(allManualRedactions.getForceRedactions().size(), 1); + assertEquals(allManualRedactions.getEntriesToAdd().size(), 1); + var entryToAdd = allManualRedactions.getEntriesToAdd() + .stream() + .findFirst() + .get(); + assertFalse(entryToAdd.isAddToDictionary()); + assertFalse(entryToAdd.isAddToDossierDictionary()); + assertEquals(entryToAdd.getValue(), darthVader); + + //bulk force + manualRedactionClient.addRedactionBulkLocal(dossier.getId(), + file.getId(), + AddRedactionBulkLocalRequestModel.builder() + .type(type1.getType()) + .value(darthVader) + .legalBasis(legal3) + .reason("reason") + .section("section") + .positions(List.of(new Rectangle(56.8f, 528.9f, 120.96f, 12.64f, 0))) + .build()); + List foundTerms = new ArrayList<>(); + foundTerms.add(new FoundTerm(position1, darthVader)); + foundTerms.add(new FoundTerm(position2, darthVader)); + foundTerms.add(new FoundTerm(position3, darthVader)); + foundTerms.add(new FoundTerm(position4, darthVader)); + + BulkLocalResponse addValueBackResponse = BulkLocalResponse.builder() + .fileId(file.getId()) + .dossierId(dossier.getId()) + .type(type1.getType()) + .legalBasis(legal3) + .reason("reason") + .section("section") + .foundTerms(foundTerms) + .userId("user") + .build(); + searchTermOccurrencesResponseReceiver.receive(addValueBackResponse); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, false); + // check that there is a link to the dictionary entries. the merge of entity log will take case of them based on the sourceId + assertEquals(allManualRedactions.getForceRedactions().size(), 1); + assertEquals(allManualRedactions.getEntriesToAdd().size(), 5); + var addLocalBulk1 = allManualRedactions.getEntriesToAdd().stream().filter(e -> convertPositions(position1).equals(e.getPositions())).findFirst(); + assertThat(addLocalBulk1.isPresent()).isTrue(); + assertThat(addLocalBulk1.get().getSourceId()).isEqualTo("AnnotationId1"); + var addLocalBulk2 = allManualRedactions.getEntriesToAdd().stream().filter(e -> convertPositions(position2).equals(e.getPositions())).findFirst(); + assertThat(addLocalBulk2.isPresent()).isTrue(); + assertThat(addLocalBulk2.get().getSourceId()).isEqualTo("AnnotationId2"); + var addLocalBulk3 = allManualRedactions.getEntriesToAdd().stream().filter(e -> convertPositions(position3).equals(e.getPositions())).findFirst(); + assertThat(addLocalBulk3.isPresent()).isTrue(); + assertThat(addLocalBulk3.get().getSourceId()).isEqualTo("AnnotationId3"); + var addLocalBulk4 = allManualRedactions.getEntriesToAdd().stream().filter(e -> convertPositions(position4).equals(e.getPositions())).findFirst(); + assertThat(addLocalBulk4.isPresent()).isTrue(); + assertThat(addLocalBulk4.get().getSourceId()).isEqualTo("AnnotationId4"); + } + + private List convertPositions(List positions) { + + return positions.stream() + .map(position -> Rectangle.builder().page(position.getPageNumber()).height(position.h()).width(position.w()).topLeftX(position.x()).topLeftY(position.y()).build()) + .toList(); + } }