RED-10425 - Annotation added twice when bulk-force while auto-analysis is disabled

- check for link with dictionary entry in the entity log after the found terms are received for an addbulklocal
- unit test added
This commit is contained in:
corinaolariu 2024-11-13 10:37:47 +02:00
parent ded782850a
commit 51010c07d2
2 changed files with 180 additions and 8 deletions

View File

@ -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<AddRedactionRequestModel> 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<Rectangle> convertPositions(List<Position> positions) {
return positions.stream()

View File

@ -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<EntityLogEntry> entityLogEntries = new ArrayList<>();
String legal2 = "Legal 2";
String legal3 = "Legal 3";
String darthVader = "Darth Vader";
List<Position> position1 = List.of(new Position(56.8f, 528.9f, 120.96f, 12.64f, 1));
List<Position> position2 = List.of(new Position(56.8f, 501.3f, 120.96f, 12.64f, 1));
List<Position> position3 = List.of(new Position(56.8f, 473.7f, 120.96f, 12.64f, 1));
List<Position> 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<FoundTerm> 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<Rectangle> convertPositions(List<Position> 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();
}
}