RED-8480: don't merge recategorizations for images, create pending entry instead

* TODO: remove filter in report-service and pdftron-redaction-service
This commit is contained in:
Ali Oezyetimoglu 2024-03-28 15:27:04 +01:00
parent 5de667b0a0
commit efa02af3fb
2 changed files with 97 additions and 18 deletions

View File

@ -4,6 +4,7 @@ import static com.iqser.red.service.persistence.management.v1.processor.utils.Ty
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@ -97,11 +98,15 @@ public class EntityLogMergeService {
if (allManualChanges.containsKey(entityLogEntry.getId())) {
mergeLocalManualChanges(dossier, allManualChanges, entityLogEntry, analysisNumber);
List<EntityLogEntry> pendingImageRecategorizations = mergeLocalManualChangesAndReturnNonMergeableAsPending(dossier,
allManualChanges,
entityLogEntry,
analysisNumber);
List<EntityLogEntry> pendingDictionaryEntries = buildPendingDictionaryEntries(allManualChanges, entityLogEntry);
// insert pending entries directly after the associated entry to enable performant linking in UI
for (EntityLogEntry pendingDictionaryEntry : pendingDictionaryEntries) {
for (EntityLogEntry pendingDictionaryEntry : concatLists(pendingDictionaryEntries, pendingImageRecategorizations)) {
numberOfAddedPendingEntries++;
entityLogEntries.add(i + numberOfAddedPendingEntries, pendingDictionaryEntry);
}
@ -117,6 +122,14 @@ public class EntityLogMergeService {
}
private static List<EntityLogEntry> concatLists(List<EntityLogEntry> pendingDictionaryEntries, List<EntityLogEntry> pendingImageRecategorizations) {
return Stream.of(pendingDictionaryEntries, pendingImageRecategorizations)
.flatMap(Collection::stream)
.toList();
}
private Stream<EntityLogEntry> buildPendingDictionaryChanges(ManualRedactions unprocessedManualRedactions) {
return unprocessedManualRedactions.getEntriesToAdd()
@ -161,25 +174,36 @@ public class EntityLogMergeService {
}
private void mergeLocalManualChanges(DossierEntity dossier, Map<String, List<BaseAnnotation>> allManualChanges, EntityLogEntry entityLogEntry, int analysisNumber) {
private List<EntityLogEntry> mergeLocalManualChangesAndReturnNonMergeableAsPending(DossierEntity dossier,
Map<String, List<BaseAnnotation>> allManualChanges,
EntityLogEntry entityLogEntry,
int analysisNumber) {
allManualChanges.getOrDefault(entityLogEntry.getId(), Collections.emptyList())
return allManualChanges.getOrDefault(entityLogEntry.getId(), Collections.emptyList())
.stream()
.filter(BaseAnnotation::isLocal)
.sorted(Comparator.comparing(BaseAnnotation::getRequestDate))
.forEach(localChange -> {
.map(localChange -> {
if (localChange instanceof IdRemoval idRemoval) {
mergeIdsToRemove(idRemoval, entityLogEntry, analysisNumber);
mergeIdToRemove(idRemoval, entityLogEntry, analysisNumber);
return null;
} else if (localChange instanceof ManualResizeRedaction manualResizeRedaction) {
mergeResizeRedactions(manualResizeRedaction, entityLogEntry, analysisNumber);
mergeResizeRedaction(manualResizeRedaction, entityLogEntry, analysisNumber);
return null;
} else if (localChange instanceof ManualLegalBasisChange manualLegalBasisChange) {
mergeLegalBasisChanges(manualLegalBasisChange, entityLogEntry, analysisNumber);
mergeLegalBasisChange(manualLegalBasisChange, entityLogEntry, analysisNumber);
return null;
} else if (localChange instanceof ManualRecategorization manualRecategorization) {
mergeRecategorizations(manualRecategorization, entityLogEntry, dossier, analysisNumber);
return mergeRecategorization(manualRecategorization, entityLogEntry, dossier, analysisNumber);
} else if (localChange instanceof ManualForceRedaction manualForceRedaction) {
mergeForceRedactions(manualForceRedaction, entityLogEntry, analysisNumber);
mergeForceRedaction(manualForceRedaction, entityLogEntry, analysisNumber);
return null;
} else {
return null;
}
});
})
.filter(Objects::nonNull)
.toList();
}
@ -268,7 +292,7 @@ public class EntityLogMergeService {
}
private void mergeIdsToRemove(IdRemoval idRemoval, EntityLogEntry entityLogEntry, int analysisNumber) {
private void mergeIdToRemove(IdRemoval idRemoval, EntityLogEntry entityLogEntry, int analysisNumber) {
entityLogEntry.setState(EntryState.IGNORED);
entityLogEntry.getEngines().add(Engine.MANUAL);
@ -285,7 +309,7 @@ public class EntityLogMergeService {
}
private void mergeResizeRedactions(ManualResizeRedaction manualResizeRedaction, EntityLogEntry entityLogEntry, int analysisNumber) {
private void mergeResizeRedaction(ManualResizeRedaction manualResizeRedaction, EntityLogEntry entityLogEntry, int analysisNumber) {
entityLogEntry.setTextAfter(manualResizeRedaction.getTextAfter());
entityLogEntry.setTextBefore(manualResizeRedaction.getTextBefore());
@ -306,7 +330,7 @@ public class EntityLogMergeService {
@Deprecated(forRemoval = true)
private void mergeLegalBasisChanges(ManualLegalBasisChange manualLegalBasisChange, EntityLogEntry entityLogEntry, int analysisNumber) {
private void mergeLegalBasisChange(ManualLegalBasisChange manualLegalBasisChange, EntityLogEntry entityLogEntry, int analysisNumber) {
entityLogEntry.setLegalBasis(manualLegalBasisChange.getLegalBasis());
entityLogEntry.setSection(manualLegalBasisChange.getSection());
@ -343,16 +367,24 @@ public class EntityLogMergeService {
}
private void mergeRecategorizations(ManualRecategorization recategorization, EntityLogEntry entityLogEntry, DossierEntity dossier, int analysisNumber) {
private EntityLogEntry mergeRecategorization(ManualRecategorization recategorization, EntityLogEntry entityLogEntry, DossierEntity dossier, int analysisNumber) {
if (entityLogEntry.getEntryType().equals(EntryType.IMAGE) || entityLogEntry.getEntryType().equals(EntryType.IMAGE_HINT)) {
return pendingDictionaryEntryFactory.buildPendingImageRecategorizationEntry(recategorization, entityLogEntry, analysisNumber);
}
boolean isHint = isHint(recategorization.getType(), dossier);
if (!Strings.isNullOrEmpty(recategorization.getType())) {
entityLogEntry.setType(recategorization.getType());
}
entityLogEntry.setEntryType(getEntryType(isHint, recategorization.getType()));
entityLogEntry.setState(isHint ? EntryState.SKIPPED : EntryState.APPLIED);
entityLogEntry.setState(isHint ? EntryState.SKIPPED : EntryState.APPLIED); // TODO: only set applied if legalBasis is set by recategorization
entityLogEntry.getEngines().add(Engine.MANUAL);
if (!Strings.isNullOrEmpty(recategorization.getLegalBasis())) {
entityLogEntry.setLegalBasis(recategorization.getLegalBasis());
}
@ -372,10 +404,15 @@ public class EntityLogMergeService {
.userId(recategorization.getUser())
.propertyChanges(getPropertyChanges(recategorization))
.build());
if ((entityLogEntry.isDictionaryEntry() || entityLogEntry.isDossierDictionaryEntry()) && !recategorization.isAddToDictionary() && !recategorization.isAddToAllDossiers()) {
entityLogEntry.setState(EntryState.REMOVED);
}
return null;
}
private Map<String, String> getPropertyChanges(ManualRecategorization recategorization) {
public static Map<String, String> getPropertyChanges(ManualRecategorization recategorization) {
Map<String, String> propertyChanges = new HashMap<>();
if (!Strings.isNullOrEmpty(recategorization.getType())) {
@ -394,7 +431,7 @@ public class EntityLogMergeService {
}
private void mergeForceRedactions(ManualForceRedaction forceRedaction, EntityLogEntry entityLogEntry, int analysisNumber) {
private void mergeForceRedaction(ManualForceRedaction forceRedaction, EntityLogEntry entityLogEntry, int analysisNumber) {
entityLogEntry.setLegalBasis(forceRedaction.getLegalBasis());
entityLogEntry.setState(entityLogEntry.getEntryType().equals(EntryType.HINT) ? EntryState.SKIPPED : EntryState.APPLIED);

View File

@ -9,6 +9,7 @@ import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogMergeService;
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.EntityLogEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState;
@ -204,4 +205,45 @@ public class PendingDictionaryEntryFactory {
.build();
}
public EntityLogEntry buildPendingImageRecategorizationEntry(ManualRecategorization manualChange, EntityLogEntry originalEntry) {
var manualChanges = List.of(ManualChange.builder()
.manualRedactionType(ManualRedactionType.RECATEGORIZE)
.requestedDate(manualChange.getRequestDate())
.processedDate(manualChange.getProcessedDate())
.userId(manualChange.getUser())
.propertyChanges(EntityLogMergeService.getPropertyChanges(manualChange))
.build());
String reason = String.format("Image has been recategorized from %s to %s", originalEntry.getType(), manualChange.getType());
return EntityLogEntry.builder()
.id(originalEntry.getId())
.value(originalEntry.getValue())
.type(manualChange.getType())
.entryType(originalEntry.getEntryType())
.state(EntryState.PENDING)
.dictionaryEntry(manualChange.isAddToDictionary())
.dossierDictionaryEntry(manualChange.isAddToAllDossiers())
.reason(reason)
.legalBasis(reason)
.matchedRule("")
.containingNodeId(Collections.emptyList())
.closestHeadline("")
.section("")
.positions(originalEntry.getPositions())
.textAfter("")
.textBefore("")
.startOffset(-1)
.endOffset(-1)
.changes(Collections.emptyList())
.manualChanges(manualChanges)
.engines(Set.of(Engine.MANUAL))
.reference(Collections.emptySet())
.importedRedactionIntersections(Collections.emptySet())
.build();
}
}