RED-8998 - Return merged entities or pending entries for manual changes.

This commit is contained in:
Andrei Isvoran 2024-05-07 10:11:35 +02:00
parent 1e64903352
commit a300f61609
10 changed files with 250 additions and 124 deletions

View File

@ -22,6 +22,7 @@ import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.TypeEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.TypeEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; 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.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.PendingDictionaryEntryFactory; import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.PendingDictionaryEntryFactory;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
@ -45,6 +46,7 @@ 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.ManualRedactionEntry; 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.entitymapped.ManualResizeRedaction;
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.dossiertemplate.type.DictionaryEntryType;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.service.EntityLogMongoService;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
import lombok.AccessLevel; import lombok.AccessLevel;
@ -60,47 +62,76 @@ public class EntityLogMergeService {
DictionaryPersistenceService dictionaryPersistenceService; DictionaryPersistenceService dictionaryPersistenceService;
PendingDictionaryEntryFactory pendingDictionaryEntryFactory; PendingDictionaryEntryFactory pendingDictionaryEntryFactory;
EntityLogMongoService entityLogMongoService;
@Observed(name = "EntityLogMergeService", contextualName = "merge-entity-log") @Observed(name = "EntityLogMergeService", contextualName = "merge-entity-log")
public EntityLog mergeEntityLog(ManualRedactions unprocessedManualRedactions, EntityLog entityLog, DossierEntity dossier) { public EntityLog mergeEntityLog(ManualRedactions unprocessedManualRedactions, EntityLog entityLog, DossierEntity dossier) {
log.debug("Merging EntityLog");
long start = System.currentTimeMillis();
final int analysisNumber = entityLog.getAnalysisNumber(); final int analysisNumber = entityLog.getAnalysisNumber();
Map<String, List<BaseAnnotation>> allManualChanges = unprocessedManualRedactions.buildAll() Map<String, List<BaseAnnotation>> allManualChanges = groupManualChanges(unprocessedManualRedactions);
.stream()
.collect(Collectors.groupingBy(BaseAnnotation::getAnnotationId));
List<EntityLogEntry> entityLogEntries = new LinkedList<>(entityLog.getEntityLogEntry()); List<EntityLogEntry> entityLogEntries = new LinkedList<>(entityLog.getEntityLogEntry());
Map<String, EntityLogEntry> addedLocalManualEntries = buildUnprocessedLocalManualRedactions(unprocessedManualRedactions, entityLog, dossier)// merge(unprocessedManualRedactions, entityLog.getEntityLogEntry(), dossier, analysisNumber, entityLogEntries, allManualChanges);
entityLog.setEntityLogEntry(entityLogEntries);
return entityLog;
}
@Observed(name = "EntityLogMergeService", contextualName = "merge-entity-log-entries")
public List<EntityLogEntry> mergeEntityLogEntries(ManualRedactions unprocessedManualRedactions, List<String> entityLogEntryIds, DossierEntity dossier, String fileId) {
final int analysisNumber = entityLogMongoService.findLatestAnalysisNumber(dossier.getId(), fileId)
.orElseThrow(() -> new BadRequestException("Can't load analysis number"));
Map<String, List<BaseAnnotation>> allManualChanges = groupManualChanges(unprocessedManualRedactions);
List<EntityLogEntry> entityLogEntries = entityLogMongoService.findEntityLogEntriesByIds(dossier.getId(), fileId, entityLogEntryIds);
merge(unprocessedManualRedactions, entityLogEntries, dossier, analysisNumber, entityLogEntries, allManualChanges);
return entityLogEntries;
}
private void merge(ManualRedactions unprocessedManualRedactions,
List<EntityLogEntry> entityLog,
DossierEntity dossier,
int analysisNumber,
List<EntityLogEntry> entityLogEntries,
Map<String, List<BaseAnnotation>> allManualChanges) {
Map<String, EntityLogEntry> addedLocalManualEntries = buildUnprocessedLocalManualRedactions(unprocessedManualRedactions, entityLog, dossier, analysisNumber)//
.collect(Collectors.toMap(EntityLogEntry::getId, Function.identity())); .collect(Collectors.toMap(EntityLogEntry::getId, Function.identity()));
entityLogEntries.addAll(addedLocalManualEntries.values()); entityLogEntries.addAll(addedLocalManualEntries.values());
buildPendingDictionaryChanges(unprocessedManualRedactions).forEach(entityLogEntries::add); buildPendingDictionaryChanges(unprocessedManualRedactions).forEach(entityLogEntries::add);
processEntityLogEntries(dossier, entityLogEntries, addedLocalManualEntries, analysisNumber, allManualChanges);
}
private void processEntityLogEntries(DossierEntity dossier,
List<EntityLogEntry> entityLogEntries,
Map<String, EntityLogEntry> addedLocalManualEntries,
int analysisNumber,
Map<String, List<BaseAnnotation>> allManualChanges) {
int numberOfAddedPendingEntries = 0; // since list is dynamically growing we need to keep track of the number of added pending entries to ignore them in the loop int numberOfAddedPendingEntries = 0; // since list is dynamically growing we need to keep track of the number of added pending entries to ignore them in the loop
for (int i = 0; i + numberOfAddedPendingEntries < entityLogEntries.size(); i++) { for (int i = 0; i + numberOfAddedPendingEntries < entityLogEntries.size(); i++) {
EntityLogEntry entityLogEntry = entityLogEntries.get(i + numberOfAddedPendingEntries); EntityLogEntry entityLogEntry = entityLogEntries.get(i + numberOfAddedPendingEntries);
if (isDuplicatedByAny(entityLogEntry, addedLocalManualEntries)) { if (isDuplicatedByAny(entityLogEntry, addedLocalManualEntries)) {
mergeOriginalAndLocallyAddedEntries(addedLocalManualEntries, entityLogEntry, analysisNumber); mergeOriginalAndLocallyAddedEntries(addedLocalManualEntries, entityLogEntry, analysisNumber);
continue; continue;
} }
if (allManualChanges.containsKey(entityLogEntry.getId())) { if (allManualChanges.containsKey(entityLogEntry.getId())) {
List<EntityLogEntry> pendingImageRecategorizations = mergeLocalManualChangesAndReturnNonMergeableAsPending(dossier, List<EntityLogEntry> pendingImageRecategorizations = mergeLocalManualChangesAndReturnNonMergeableAsPending(dossier,
allManualChanges, allManualChanges,
entityLogEntry, entityLogEntry,
analysisNumber); analysisNumber);
List<EntityLogEntry> pendingDictionaryEntries = buildPendingDictionaryEntries(allManualChanges, entityLogEntry); List<EntityLogEntry> pendingDictionaryEntries = buildPendingDictionaryEntries(allManualChanges, entityLogEntry);
// insert pending entries directly after the associated entry to enable performant linking in UI // insert pending entries directly after the associated entry to enable performant linking in UI
@ -108,15 +139,16 @@ public class EntityLogMergeService {
numberOfAddedPendingEntries++; numberOfAddedPendingEntries++;
entityLogEntries.add(i + numberOfAddedPendingEntries, pendingDictionaryEntry); entityLogEntries.add(i + numberOfAddedPendingEntries, pendingDictionaryEntry);
} }
}
}
} }
}
entityLog.setEntityLogEntry(entityLogEntries); private Map<String, List<BaseAnnotation>> groupManualChanges(ManualRedactions unprocessedManualRedactions) {
log.debug("EntityLog merged successfully in {} ms.", System.currentTimeMillis() - start); return unprocessedManualRedactions.buildAll()
return entityLog; .stream()
.collect(Collectors.groupingBy(BaseAnnotation::getAnnotationId));
} }
@ -149,12 +181,15 @@ public class EntityLogMergeService {
} }
private Stream<EntityLogEntry> buildUnprocessedLocalManualRedactions(ManualRedactions unprocessedManualRedactions, EntityLog entityLog, DossierEntity dossier) { private Stream<EntityLogEntry> buildUnprocessedLocalManualRedactions(ManualRedactions unprocessedManualRedactions,
List<EntityLogEntry> entityLogEntries,
DossierEntity dossier,
int analysisNumber) {
return unprocessedManualRedactions.getEntriesToAdd() return unprocessedManualRedactions.getEntriesToAdd()
.stream() .stream()
.filter(ManualRedactionEntry::isLocal) .filter(ManualRedactionEntry::isLocal)
.map(manualRedactionEntry -> mergeManualRedactionEntries(manualRedactionEntry, entityLog, dossier)) .map(manualRedactionEntry -> mergeManualRedactionEntries(manualRedactionEntry, entityLogEntries, dossier, analysisNumber))
.filter(Optional::isPresent) .filter(Optional::isPresent)
.map(Optional::get); .map(Optional::get);
} }
@ -217,27 +252,27 @@ public class EntityLogMergeService {
} }
private Optional<EntityLogEntry> mergeManualRedactionEntries(ManualRedactionEntry manualRedactionEntry, EntityLog entityLog, DossierEntity dossier) { private Optional<EntityLogEntry> mergeManualRedactionEntries(ManualRedactionEntry manualRedactionEntry,
List<EntityLogEntry> entityLogEntries,
DossierEntity dossier,
int analysisNumber) {
if (manualRedactionEntry.getPositions() == null || manualRedactionEntry.getPositions().isEmpty()) { if (manualRedactionEntry.getPositions() == null || manualRedactionEntry.getPositions().isEmpty()) {
return Optional.empty(); return Optional.empty();
} }
if (isFalsePositive(manualRedactionEntry)) { if (isFalsePositive(manualRedactionEntry)) {
var matchingEntities = entityLog.getEntityLogEntry() var matchingEntities = entityLogEntries.stream()
.stream()
.filter(entityLogEntry -> equalPosition(manualRedactionEntry.getPositions() .filter(entityLogEntry -> equalPosition(manualRedactionEntry.getPositions()
.get(0), .get(0),
entityLogEntry.getPositions() entityLogEntry.getPositions()
.get(0))) .get(0)))
.toList(); .toList();
matchingEntities.forEach(matchingEntity -> mergeFalsePositive(entityLog, matchingEntity)); matchingEntities.forEach(matchingEntity -> mergeFalsePositive(analysisNumber, matchingEntity));
return Optional.empty(); return Optional.empty();
} }
EntityLogEntry entityLogEntry = buildEntityLogEntry(manualRedactionEntry, entityLog.getAnalysisNumber(), dossier); return Optional.of(buildEntityLogEntry(manualRedactionEntry, analysisNumber, dossier));
entityLog.getEntityLogEntry().add(entityLogEntry);
return Optional.of(entityLogEntry);
} }
@ -288,11 +323,11 @@ public class EntityLogMergeService {
} }
private void mergeFalsePositive(EntityLog entityLog, EntityLogEntry existingEntry) { private void mergeFalsePositive(int analysisNumber, EntityLogEntry existingEntry) {
existingEntry.setState(EntryState.REMOVED); existingEntry.setState(EntryState.REMOVED);
List<Change> falsePositiveChanges = new ArrayList<>(); List<Change> falsePositiveChanges = new ArrayList<>();
falsePositiveChanges.add(Change.builder().analysisNumber(entityLog.getAnalysisNumber()).dateTime(OffsetDateTime.now()).type(ChangeType.REMOVED).build()); falsePositiveChanges.add(Change.builder().analysisNumber(analysisNumber).dateTime(OffsetDateTime.now()).type(ChangeType.REMOVED).build());
if (existingEntry.getChanges() != null && !existingEntry.getChanges().isEmpty()) { if (existingEntry.getChanges() != null && !existingEntry.getChanges().isEmpty()) {
existingEntry.getChanges().addAll(falsePositiveChanges); existingEntry.getChanges().addAll(falsePositiveChanges);
} else { } else {
@ -342,13 +377,13 @@ public class EntityLogMergeService {
public EntityLogEntry mergeRecategorization(ManualRecategorization recategorization, EntityLogEntry entityLogEntry, DossierEntity dossier, int analysisNumber) { public EntityLogEntry mergeRecategorization(ManualRecategorization recategorization, EntityLogEntry entityLogEntry, DossierEntity dossier, int analysisNumber) {
if ((recategorization.getType() != null && !Objects.equals(recategorization.getType(), entityLogEntry.getType()) && Strings.isNullOrEmpty(recategorization.getLegalBasis()))// if ((recategorization.getType() != null && !Objects.equals(recategorization.getType(), entityLogEntry.getType()) && Strings.isNullOrEmpty(recategorization.getLegalBasis()))
//
&& (entityLogEntry.getEntryType().equals(EntryType.IMAGE) || entityLogEntry.getEntryType().equals(EntryType.IMAGE_HINT))) { && (entityLogEntry.getEntryType().equals(EntryType.IMAGE) || entityLogEntry.getEntryType().equals(EntryType.IMAGE_HINT))) {
return pendingDictionaryEntryFactory.buildPendingImageRecategorizationEntry(recategorization, entityLogEntry); return pendingDictionaryEntryFactory.buildPendingImageRecategorizationEntry(recategorization, entityLogEntry);
} }
entityLogEntry.getEngines().add(Engine.MANUAL); entityLogEntry.getEngines().add(Engine.MANUAL);
if (recategorization.getType() != null && !recategorization.getType().equals(entityLogEntry.getType())) { if (recategorization.getType() != null && !recategorization.getType().equals(entityLogEntry.getType())) {

View File

@ -0,0 +1,50 @@
package com.iqser.red.service.persistence.management.v1.processor.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.service.EntityLogMongoService;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class EntityLogMongoWrapperService {
private final DossierService dossierService;
private final EntityLogMongoService entityLogMongoService;
private final ManualRedactionProviderService manualRedactionProviderService;
private final EntityLogMergeService entityLogMergeService;
public EntityLogEntry getEntityLogEntryById(String dossierId, String fileId, String annotationId) {
return entityLogMongoService.findEntityLogEntryById(dossierId, fileId, annotationId)
.orElseThrow(() -> new NotFoundException(getEntityLogNotEntryFoundErrorMessage(annotationId)));
}
public List<EntityLogEntry> getEntityLogEntriesByIds(String dossierId, String fileId, List<String> ids, boolean includeUnprocessed) {
List<EntityLogEntry> entityLogEntries = entityLogMongoService.findEntityLogEntriesByIds(dossierId, fileId, ids);
if (includeUnprocessed) {
DossierEntity dossier = dossierService.getDossierById(dossierId);
ManualRedactions unprocessedManualRedactions = manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.unprocessedOnly());
entityLogEntries = entityLogMergeService.mergeEntityLogEntries(unprocessedManualRedactions, entityLogEntries.stream().map(EntityLogEntry::getId).toList(), dossier, fileId);
}
return entityLogEntries;
}
private static String getEntityLogNotEntryFoundErrorMessage(String annotationId) {
return String.format("EntityLogEntry does not exist for annotationId ID \"%s\"!", annotationId);
}
}

View File

@ -5,7 +5,6 @@ import static com.iqser.red.service.persistence.management.v1.processor.utils.Ty
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -14,6 +13,8 @@ import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRecategorizationEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRecategorizationEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; 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.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogMongoWrapperService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RequestEntryPair;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Engine; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Engine;
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.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry;
@ -23,7 +24,6 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations
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.LegalBasisChangeRequest;
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.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.RemoveRedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RequestEntryPair;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ResizeRedactionRequest; 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.dossier.Dossier; 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.DictionaryEntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType;
@ -33,7 +33,6 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.Lega
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.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.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.manual.ResizeRedactionRequestModel;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.service.EntityLogMongoService;
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
@ -46,7 +45,7 @@ import lombok.experimental.FieldDefaults;
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class ManualRedactionMapper { public class ManualRedactionMapper {
EntityLogMongoService entityLogMongoService; EntityLogMongoWrapperService entityLogMongoWrapperService;
@Observed(name = "ManualRedactionMapper", contextualName = "to-add-redaction-request-list") @Observed(name = "ManualRedactionMapper", contextualName = "to-add-redaction-request-list")
@ -86,11 +85,16 @@ public class ManualRedactionMapper {
Set<RemoveRedactionRequestModel> removeRedactionRequests, Set<RemoveRedactionRequestModel> removeRedactionRequests,
boolean includeUnprocessed) { boolean includeUnprocessed) {
List<EntityLogEntry> entityLogEntries = entityLogMongoWrapperService.getEntityLogEntriesByIds(dossierId,
fileId,
removeRedactionRequests.stream()
.map(RemoveRedactionRequestModel::getAnnotationId)
.toList(),
includeUnprocessed);
List<RequestEntryPair<RemoveRedactionRequest>> requests = new ArrayList<>(); List<RequestEntryPair<RemoveRedactionRequest>> requests = new ArrayList<>();
for (var removeRedactionRequest : removeRedactionRequests) { for (var removeRedactionRequest : removeRedactionRequests) {
Optional<EntityLogEntry> optionalEntityLogEntry = entityLogMongoService.findEntityLogEntryById(dossierId, fileId, removeRedactionRequest.getAnnotationId()); entityLogEntries.forEach(entityLogEntry -> {
optionalEntityLogEntry.ifPresent(entityLogEntry -> {
var request = RemoveRedactionRequest.builder() var request = RemoveRedactionRequest.builder()
.annotationId(removeRedactionRequest.getAnnotationId()) .annotationId(removeRedactionRequest.getAnnotationId())
.user(KeycloakSecurity.getUserId()) .user(KeycloakSecurity.getUserId())
@ -106,10 +110,7 @@ public class ManualRedactionMapper {
request.comment(removeRedactionRequest.getComment()); request.comment(removeRedactionRequest.getComment());
} }
requests.add(RequestEntryPair.<RemoveRedactionRequest>builder() requests.add(RequestEntryPair.<RemoveRedactionRequest>builder().request(request.build()).entityLogEntry(entityLogEntry).build());
.request(request.build())
.entityLogEntry(entityLogEntry)
.build());
}); });
} }
@ -126,8 +127,7 @@ public class ManualRedactionMapper {
for (ForceRedactionRequestModel forceRedactionRequestModel : forceRedactionRequests) { for (ForceRedactionRequestModel forceRedactionRequestModel : forceRedactionRequests) {
Optional<EntityLogEntry> optionalEntityLogEntry = entityLogMongoService.findEntityLogEntryById(dossierId, fileId, forceRedactionRequestModel.getAnnotationId()); EntityLogEntry entityLogEntry = entityLogMongoWrapperService.getEntityLogEntryById(dossierId, fileId, forceRedactionRequestModel.getAnnotationId());
optionalEntityLogEntry.ifPresent(entityLogEntry -> {
ForceRedactionRequest request = ForceRedactionRequest.builder() ForceRedactionRequest request = ForceRedactionRequest.builder()
.annotationId(forceRedactionRequestModel.getAnnotationId()) .annotationId(forceRedactionRequestModel.getAnnotationId())
.user(KeycloakSecurity.getUserId()) .user(KeycloakSecurity.getUserId())
@ -139,11 +139,7 @@ public class ManualRedactionMapper {
manualRedactionEntryConsumer.accept(entityLogEntry); manualRedactionEntryConsumer.accept(entityLogEntry);
} }
requests.add(RequestEntryPair.<ForceRedactionRequest>builder() requests.add(RequestEntryPair.<ForceRedactionRequest>builder().request(request).entityLogEntry(entityLogEntry).build());
.request(request)
.entityLogEntry(entityLogEntry)
.build());
});
} }
return requests; return requests;
@ -160,8 +156,7 @@ public class ManualRedactionMapper {
for (LegalBasisChangeRequestModel legalBasisChangeRequest : legalBasisChangeRequests) { for (LegalBasisChangeRequestModel legalBasisChangeRequest : legalBasisChangeRequests) {
Optional<EntityLogEntry> optionalEntityLogEntry = entityLogMongoService.findEntityLogEntryById(dossierId, fileId, legalBasisChangeRequest.getAnnotationId()); EntityLogEntry entityLogEntry = entityLogMongoWrapperService.getEntityLogEntryById(dossierId, fileId, legalBasisChangeRequest.getAnnotationId());
optionalEntityLogEntry.ifPresent(entityLogEntry -> {
LegalBasisChangeRequest request = LegalBasisChangeRequest.builder() LegalBasisChangeRequest request = LegalBasisChangeRequest.builder()
.annotationId(legalBasisChangeRequest.getAnnotationId()) .annotationId(legalBasisChangeRequest.getAnnotationId())
.user(KeycloakSecurity.getUserId()) .user(KeycloakSecurity.getUserId())
@ -175,11 +170,7 @@ public class ManualRedactionMapper {
manualRedactionEntryConsumer.accept(entityLogEntry); manualRedactionEntryConsumer.accept(entityLogEntry);
} }
requests.add(RequestEntryPair.<LegalBasisChangeRequest>builder() requests.add(RequestEntryPair.<LegalBasisChangeRequest>builder().request(request).entityLogEntry(entityLogEntry).build());
.request(request)
.entityLogEntry(entityLogEntry)
.build());
});
} }
return requests; return requests;
@ -193,13 +184,18 @@ public class ManualRedactionMapper {
boolean includeUnprocessed, boolean includeUnprocessed,
Consumer<EntityLogEntry> manualRedactionEntryConsumer) { Consumer<EntityLogEntry> manualRedactionEntryConsumer) {
List<EntityLogEntry> entityLogEntries = entityLogMongoWrapperService.getEntityLogEntriesByIds(dossierId,
fileId,
recategorizationRequests.stream()
.map(RecategorizationRequestModel::getAnnotationId)
.toList(),
includeUnprocessed);
List<RequestEntryPair<RecategorizationRequest>> requests = new ArrayList<>(); List<RequestEntryPair<RecategorizationRequest>> requests = new ArrayList<>();
for (RecategorizationRequestModel recategorizationRequest : recategorizationRequests) { for (RecategorizationRequestModel recategorizationRequest : recategorizationRequests) {
Optional<EntityLogEntry> optionalEntityLogEntry = entityLogMongoService.findEntityLogEntryById(dossierId, fileId, recategorizationRequest.getAnnotationId()); entityLogEntries.forEach(entityLogEntry -> {
optionalEntityLogEntry.ifPresent(entityLogEntry -> {
String changedValue; String changedValue;
String changedTypeId; String changedTypeId;
@ -241,10 +237,7 @@ public class ManualRedactionMapper {
manualRedactionEntryConsumer.accept(entityLogEntry); manualRedactionEntryConsumer.accept(entityLogEntry);
} }
requests.add(RequestEntryPair.<RecategorizationRequest>builder() requests.add(RequestEntryPair.<RecategorizationRequest>builder().request(request).entityLogEntry(entityLogEntry).build());
.request(request)
.entityLogEntry(entityLogEntry)
.build());
}); });
} }
@ -282,14 +275,21 @@ public class ManualRedactionMapper {
public List<RequestEntryPair<ResizeRedactionRequest>> toResizeRedactionRequestList(String dossierId, public List<RequestEntryPair<ResizeRedactionRequest>> toResizeRedactionRequestList(String dossierId,
String fileId, String fileId,
Set<ResizeRedactionRequestModel> resizeRedactionRequests, Set<ResizeRedactionRequestModel> resizeRedactionRequests,
Consumer<EntityLogEntry> manualRedactionEntryConsumer) { Consumer<EntityLogEntry> manualRedactionEntryConsumer,
boolean includeUnprocessed) {
List<EntityLogEntry> entityLogEntries = entityLogMongoWrapperService.getEntityLogEntriesByIds(dossierId,
fileId,
resizeRedactionRequests.stream()
.map(ResizeRedactionRequestModel::getAnnotationId)
.toList(),
includeUnprocessed);
List<RequestEntryPair<ResizeRedactionRequest>> requests = new ArrayList<>(); List<RequestEntryPair<ResizeRedactionRequest>> requests = new ArrayList<>();
for (ResizeRedactionRequestModel resizeRedactionRequest : resizeRedactionRequests) { for (ResizeRedactionRequestModel resizeRedactionRequest : resizeRedactionRequests) {
Optional<EntityLogEntry> optionalEntityLogEntry = entityLogMongoService.findEntityLogEntryById(dossierId, fileId, resizeRedactionRequest.getAnnotationId()); entityLogEntries.forEach(entityLogEntry -> {
optionalEntityLogEntry.ifPresent(entityLogEntry -> {
ResizeRedactionRequest request = ResizeRedactionRequest.builder() ResizeRedactionRequest request = ResizeRedactionRequest.builder()
.annotationId(resizeRedactionRequest.getAnnotationId()) .annotationId(resizeRedactionRequest.getAnnotationId())
.user(KeycloakSecurity.getUserId()) .user(KeycloakSecurity.getUserId())
@ -308,11 +308,9 @@ public class ManualRedactionMapper {
manualRedactionEntryConsumer.accept(entityLogEntry); manualRedactionEntryConsumer.accept(entityLogEntry);
} }
requests.add(RequestEntryPair.<ResizeRedactionRequest>builder() requests.add(RequestEntryPair.<ResizeRedactionRequest>builder().request(request).entityLogEntry(entityLogEntry).build());
.request(request)
.entityLogEntry(entityLogEntry)
.build());
}); });
} }
return requests; return requests;

View File

@ -108,6 +108,7 @@ public class ManualRedactionService {
ManualRedactionMapper manualRedactionMapper; ManualRedactionMapper manualRedactionMapper;
RabbitTemplate rabbitTemplate; RabbitTemplate rabbitTemplate;
EntityLogMergeService entityLogMergeService; EntityLogMergeService entityLogMergeService;
PendingDictionaryEntryFactory pendingDictionaryEntryFactory;
@Transactional @Transactional
@ -138,11 +139,17 @@ public class ManualRedactionService {
addRedactionPersistenceService.updateModifiedDictionaries(fileId, annotationId, !typeIdsOfModifiedDictionaries.isEmpty(), typeIdsOfModifiedDictionaries); addRedactionPersistenceService.updateModifiedDictionaries(fileId, annotationId, !typeIdsOfModifiedDictionaries.isEmpty(), typeIdsOfModifiedDictionaries);
EntityLogEntry entityLogEntry = null; EntityLogEntry entityLogEntry;
if (!addRedactionRequest.isAddToDictionary() && !addRedactionRequest.isAddToAllDossiers()) { if (!addRedactionRequest.isAddToDictionary() && !addRedactionRequest.isAddToAllDossiers()) {
entityLogEntry = entityLogMergeService.buildEntityLogEntry(MagicConverter.convert(manualRedactionEntryEntity, ManualRedactionEntry.class, new ManualRedactionEntryMapper()), entityLogEntry = entityLogMergeService.buildEntityLogEntry(MagicConverter.convert(manualRedactionEntryEntity,
ManualRedactionEntry.class,
new ManualRedactionEntryMapper()),
getAnalysisNumber(dossierId, fileId), getAnalysisNumber(dossierId, fileId),
dossierEntity); dossierEntity);
} else {
entityLogEntry = pendingDictionaryEntryFactory.buildAddToDictionaryEntry(MagicConverter.convert(manualRedactionEntryEntity,
ManualRedactionEntry.class,
new ManualRedactionEntryMapper()));
} }
Long commentId = commentService.addCommentAndGetId(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser()); Long commentId = commentService.addCommentAndGetId(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser());
response.add(ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).entityLogEntry(entityLogEntry).build()); response.add(ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).entityLogEntry(entityLogEntry).build());
@ -219,6 +226,8 @@ public class ManualRedactionService {
if (!idRemoval.isRemoveFromAllDossiers() && !idRemoval.isRemoveFromDictionary()) { if (!idRemoval.isRemoveFromAllDossiers() && !idRemoval.isRemoveFromDictionary()) {
entityLogMergeService.mergeIdToRemove(MagicConverter.convert(idRemoval, IdRemoval.class), entityLogEntry, getAnalysisNumber(dossierId, fileId)); entityLogMergeService.mergeIdToRemove(MagicConverter.convert(idRemoval, IdRemoval.class), entityLogEntry, getAnalysisNumber(dossierId, fileId));
} else {
entityLogEntry = pendingDictionaryEntryFactory.buildRemoveFromDictionary(MagicConverter.convert(idRemoval, IdRemoval.class), entityLogEntry);
} }
response.add(ManualAddResponse.builder().annotationId(removeRedactionRequest.getAnnotationId()).commentId(commentId).entityLogEntry(entityLogEntry).build()); response.add(ManualAddResponse.builder().annotationId(removeRedactionRequest.getAnnotationId()).commentId(commentId).entityLogEntry(entityLogEntry).build());
} }
@ -339,10 +348,19 @@ public class ManualRedactionService {
recategorizationRequest.getUser()); recategorizationRequest.getUser());
if (!recategorizationRequest.isAddToAllDossiers() && !recategorizationRequest.isAddToDictionary()) { if (!recategorizationRequest.isAddToAllDossiers() && !recategorizationRequest.isAddToDictionary()) {
entityLogMergeService.mergeRecategorization(MagicConverter.convert(recategorizationEntity, ManualRecategorization.class, new ManualRecategorizationMapper()), var entry = entityLogMergeService.mergeRecategorization(MagicConverter.convert(recategorizationEntity,
ManualRecategorization.class,
new ManualRecategorizationMapper()),
entityLogEntry, entityLogEntry,
dossierEntity, dossierEntity,
getAnalysisNumber(dossierId, fileId)); getAnalysisNumber(dossierId, fileId));
if (entry != null) {
entityLogEntry = entry;
}
} else {
entityLogEntry = pendingDictionaryEntryFactory.buildRecategorizeWithDictionary(MagicConverter.convert(recategorizationEntity,
ManualRecategorization.class,
new ManualRecategorizationMapper()), entityLogEntry);
} }
response.add(ManualAddResponse.builder().annotationId(recategorizationRequest.getAnnotationId()).commentId(commentId).entityLogEntry(entityLogEntry).build()); response.add(ManualAddResponse.builder().annotationId(recategorizationRequest.getAnnotationId()).commentId(commentId).entityLogEntry(entityLogEntry).build());
@ -366,7 +384,8 @@ public class ManualRedactionService {
List<RequestEntryPair<ResizeRedactionRequest>> requests = manualRedactionMapper.toResizeRedactionRequestList(dossierId, List<RequestEntryPair<ResizeRedactionRequest>> requests = manualRedactionMapper.toResizeRedactionRequestList(dossierId,
fileId, fileId,
resizeRedactionRequests, resizeRedactionRequests,
getEntityLogEntryConsumer(fileId)); getEntityLogEntryConsumer(fileId),
includeUnprocessed);
for (RequestEntryPair<ResizeRedactionRequest> resizeRedactionRequestRequestEntryPair : requests) { for (RequestEntryPair<ResizeRedactionRequest> resizeRedactionRequestRequestEntryPair : requests) {
@ -392,7 +411,13 @@ public class ManualRedactionService {
typeIdsOfModifiedDictionaries); typeIdsOfModifiedDictionaries);
if (!resizeRedactionRequest.isAddToAllDossiers() && !resizeRedactionRequest.getUpdateDictionary()) { if (!resizeRedactionRequest.isAddToAllDossiers() && !resizeRedactionRequest.getUpdateDictionary()) {
entityLogMergeService.mergeResizeRedaction(MagicConverter.convert(resizeRedaction, ManualResizeRedaction.class, new ManualResizeRedactionMapper()), entityLogEntry, getAnalysisNumber(dossierId, fileId)); entityLogMergeService.mergeResizeRedaction(MagicConverter.convert(resizeRedaction, ManualResizeRedaction.class, new ManualResizeRedactionMapper()),
entityLogEntry,
getAnalysisNumber(dossierId, fileId));
} else {
entityLogEntry = pendingDictionaryEntryFactory.buildResizeWithDictionary(MagicConverter.convert(resizeRedaction,
ManualResizeRedaction.class,
new ManualResizeRedactionMapper()), entityLogEntry);
} }
response.add(ManualAddResponse.builder().annotationId(resizeRedactionRequest.getAnnotationId()).commentId(commentId).entityLogEntry(entityLogEntry).build()); response.add(ManualAddResponse.builder().annotationId(resizeRedactionRequest.getAnnotationId()).commentId(commentId).entityLogEntry(entityLogEntry).build());
} }

View File

@ -171,7 +171,7 @@ public class PendingDictionaryEntryFactory {
.propertyChanges(Map.of("type", .propertyChanges(Map.of("type",
manualChange.getType(), manualChange.getType(),
"legalBasis", "legalBasis",
manualChange.getLegalBasis(), manualChange.getLegalBasis() == null ? "" : manualChange.getLegalBasis(),
"section", "section",
manualChange.getSection(), manualChange.getSection(),
"value", "value",

View File

@ -56,6 +56,7 @@ 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.ManualResizeRedaction; 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.dossier.file.FileModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel;
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.dossiertemplate.type.DictionaryEntryType;
import com.iqser.red.service.persistence.service.v1.api.shared.mongo.service.EntityLogMongoService;
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
public class EntityLogMergeTest { public class EntityLogMergeTest {
@ -87,6 +88,9 @@ public class EntityLogMergeTest {
@MockBean @MockBean
private FileStatusPersistenceService fileStatusPersistenceService; private FileStatusPersistenceService fileStatusPersistenceService;
@MockBean
private EntityLogMongoService entityLogMongoService;
@Captor @Captor
private ArgumentCaptor<AnalyzeRequest> captor; private ArgumentCaptor<AnalyzeRequest> captor;
@ -96,7 +100,7 @@ public class EntityLogMergeTest {
@BeforeEach @BeforeEach
public void setUp() { public void setUp() {
entityLogMergeService = new EntityLogMergeService(dictionaryPersistenceService, new PendingDictionaryEntryFactory()); entityLogMergeService = new EntityLogMergeService(dictionaryPersistenceService, new PendingDictionaryEntryFactory(), entityLogMongoService);
} }

View File

@ -367,7 +367,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
String fileId = file.getId(); String fileId = file.getId();
var type = typeProvider.testAndProvideType(dossierTemplate, null, "manual"); var type = typeProvider.testAndProvideType(dossierTemplate, null, "manual");
typeProvider.testAndProvideType(dossierTemplate, null, "new-type", false, 2000);
var annotationId = "imagine_this_makes_sense"; var annotationId = "imagine_this_makes_sense";
EntityLog entityLog = new EntityLog(1, EntityLog entityLog = new EntityLog(1,
1, 1,
@ -398,6 +398,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
0, 0,
0); 0);
fileManagementStorageService.saveEntityLog(dossier.getId(), file.getId(), entityLog);
when(entityLogService.getEntityLog(any(), any(), anyBoolean())).thenReturn(entityLog); when(entityLogService.getEntityLog(any(), any(), anyBoolean())).thenReturn(entityLog);
assertThat(fileClient.getDossierStatus(dossier.getId()).size()).isEqualTo(1); assertThat(fileClient.getDossierStatus(dossier.getId()).size()).isEqualTo(1);

View File

@ -2010,7 +2010,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
.annotationId("annotationId") .annotationId("annotationId")
.addToDictionary(true) .addToDictionary(true)
.addToAllDossiers(true) .addToAllDossiers(true)
.legalBasis("") .legalBasis("legalBasis")
.section("section") .section("section")
.value("other value") .value("other value")
.build(); .build();

View File

@ -53,6 +53,10 @@ public interface EntityLogEntryDocumentRepository extends MongoRepository<Entity
Optional<EntityLogEntryDocument> findEntityLogEntryDocumentByEntryId(String entityLogId, String entryId); Optional<EntityLogEntryDocument> findEntityLogEntryDocumentByEntryId(String entityLogId, String entryId);
@Query(value = "{ 'entityLogId': ?0, 'entryId': { $in: ?1 } }")
List<EntityLogEntryDocument> findEntityLogEntryDocumentsByEntryIds(String entityLogId, List<String> entryIds);
@Query(value = "{ 'entityLogId' : ?0}", delete = true) @Query(value = "{ 'entityLogId' : ?0}", delete = true)
void deleteByEntityLogId(String entityLogId); void deleteByEntityLogId(String entityLogId);

View File

@ -117,6 +117,7 @@ public class EntityLogMongoService {
entityLogDocumentRepository.save(entityLogDocument); entityLogDocumentRepository.save(entityLogDocument);
} }
public void saveEntityLogEntries(String dossierId, String fileId, List<EntityLogEntry> entityLogEntries) { public void saveEntityLogEntries(String dossierId, String fileId, List<EntityLogEntry> entityLogEntries) {
String entityLogId = mapper.getLogId(dossierId, fileId); String entityLogId = mapper.getLogId(dossierId, fileId);
@ -134,7 +135,6 @@ public class EntityLogMongoService {
} }
public void updateEntityLogEntries(String dossierId, String fileId, List<EntityLogEntry> entityLogEntries) { public void updateEntityLogEntries(String dossierId, String fileId, List<EntityLogEntry> entityLogEntries) {
String entityLogId = mapper.getLogId(dossierId, fileId); String entityLogId = mapper.getLogId(dossierId, fileId);
@ -188,6 +188,15 @@ public class EntityLogMongoService {
} }
public List<EntityLogEntry> findEntityLogEntriesByIds(String dossierId, String fileId, List<String> entryIds) {
return entityLogEntryDocumentRepository.findEntityLogEntryDocumentsByEntryIds(mapper.getLogId(dossierId, fileId), entryIds)
.stream()
.map(mapper::fromLogEntryDocument)
.collect(Collectors.toList());
}
public boolean entityLogDocumentExists(String dossierId, String fileId) { public boolean entityLogDocumentExists(String dossierId, String fileId) {
return entityLogDocumentRepository.existsById(mapper.getLogId(dossierId, fileId)); return entityLogDocumentRepository.existsById(mapper.getLogId(dossierId, fileId));
@ -210,8 +219,6 @@ public class EntityLogMongoService {
} }
public Set<Integer> findFirstContainingNodeIdForEachEntry(String dossierId, String fileId, Collection<String> entryIds) { public Set<Integer> findFirstContainingNodeIdForEachEntry(String dossierId, String fileId, Collection<String> entryIds) {
String entityLogId = mapper.getLogId(dossierId, fileId); String entityLogId = mapper.getLogId(dossierId, fileId);
@ -297,6 +304,7 @@ public class EntityLogMongoService {
return optionalEntityLog; return optionalEntityLog;
} }
public List<EntityLogEntry> findEntityLogEntriesByAnalysisNumber(String dossierId, String fileId, int analysisNumber) { public List<EntityLogEntry> findEntityLogEntriesByAnalysisNumber(String dossierId, String fileId, int analysisNumber) {
return entityLogEntryDocumentRepository.findByEntityLogIdAndChangesAnalysisNumberEquals(mapper.getLogId(dossierId, fileId), analysisNumber) return entityLogEntryDocumentRepository.findByEntityLogIdAndChangesAnalysisNumberEquals(mapper.getLogId(dossierId, fileId), analysisNumber)
@ -305,6 +313,7 @@ public class EntityLogMongoService {
.toList(); .toList();
} }
public Optional<EntityLog> findEntityLogWithEntriesByAnalysisNumber(String dossierId, String fileId, Integer analysisNumber) { public Optional<EntityLog> findEntityLogWithEntriesByAnalysisNumber(String dossierId, String fileId, Integer analysisNumber) {
String entityLogId = mapper.getLogId(dossierId, fileId); String entityLogId = mapper.getLogId(dossierId, fileId);