RED-8480: don't merge recategorizations for images, create pending entry instead #411
@ -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;
|
||||
@ -96,11 +97,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);
|
||||
}
|
||||
@ -116,6 +121,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()
|
||||
@ -160,25 +173,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();
|
||||
}
|
||||
|
||||
|
||||
@ -269,7 +293,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);
|
||||
@ -286,7 +310,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());
|
||||
@ -312,7 +336,7 @@ public class EntityLogMergeService {
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
@ -351,25 +375,39 @@ 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);
|
||||
}
|
||||
|
||||
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());
|
||||
entityLogEntry.setState(isHint ? EntryState.SKIPPED : EntryState.APPLIED);
|
||||
} else {
|
||||
entityLogEntry.setState(EntryState.SKIPPED);
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(recategorization.getSection())) {
|
||||
entityLogEntry.setSection(recategorization.getSection());
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(recategorization.getValue())) {
|
||||
entityLogEntry.setValue(recategorization.getValue());
|
||||
}
|
||||
|
||||
addChanges(entityLogEntry.getChanges(), ChangeType.CHANGED, analysisNumber, recategorization.getRequestDate());
|
||||
entityLogEntry.getManualChanges()
|
||||
.add(ManualChange.builder()
|
||||
@ -383,10 +421,11 @@ public class EntityLogMergeService {
|
||||
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())) {
|
||||
@ -405,7 +444,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);
|
||||
|
||||
@ -52,7 +52,7 @@ public class ManualRedactionDictionaryUpdateHandler {
|
||||
|
||||
public Set<String> handleAddToDictionaryAndReturnModifiedTypeIds(String fileId, String value, ManualRequestWithAddToDictionary manualRequestWithAddToDictionary) {
|
||||
|
||||
if (!manualRequestWithAddToDictionary.isAddToDictionary()) {
|
||||
if (!manualRequestWithAddToDictionary.isAddToDictionary() || value == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Set<String> typeIdsOfModifiedDictionaries = new HashSet<>();
|
||||
@ -99,7 +99,7 @@ public class ManualRedactionDictionaryUpdateHandler {
|
||||
|
||||
public Set<String> handleRemoveFromDictionaryAndReturnModifiedTypeIds(String fileId, ManualRequestWithRemoveFromDictionary manualRequestWithRemoveFromDictionary) {
|
||||
|
||||
if (!manualRequestWithRemoveFromDictionary.isRemoveFromDictionary()) {
|
||||
if (!manualRequestWithRemoveFromDictionary.isRemoveFromDictionary() || manualRequestWithRemoveFromDictionary.getValue() == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
String dossierId = manualRequestWithRemoveFromDictionary.getDossierId();
|
||||
|
||||
@ -191,13 +191,12 @@ public class ManualRedactionMapper {
|
||||
.addToDictionary(recategorizationRequest.isAddToDictionary())
|
||||
.addToAllDossiers(recategorizationRequest.isAddToAllDossiers())
|
||||
.dictionaryEntryType(getDictionaryEntryType(entityLogEntry))
|
||||
.value(entityLogEntry.getValue())
|
||||
.value(recategorizationRequest.getValue())
|
||||
.typeToRemove(entityLogEntry.getType())
|
||||
.dossierTemplateTypeId(toTypeId(recategorizationRequest.getType(), dossierTemplateId))
|
||||
.legalBasis(Optional.ofNullable(recategorizationRequest.getLegalBasis())
|
||||
.orElse(""))
|
||||
.section(recategorizationRequest.getSection())
|
||||
.value(recategorizationRequest.getValue())
|
||||
.build();
|
||||
|
||||
if (!entityLogEntry.getEngines().contains(Engine.MANUAL) && !recategorizationRequest.isAddToAllDossiers() && !recategorizationRequest.isAddToDictionary()) {
|
||||
|
||||
@ -240,6 +240,7 @@ public class ManualRedactionService {
|
||||
Set<String> typeIdsOfDictionariesWithAdd = manualRedactionDictionaryUpdateHandler.handleAddToDictionaryAndReturnModifiedTypeIds(fileId,
|
||||
recategorizationRequest.getValue(),
|
||||
recategorizationRequest);
|
||||
|
||||
Set<String> typeIdsOfDictionariesWithDelete = manualRedactionDictionaryUpdateHandler.handleRemoveFromDictionaryAndReturnModifiedTypeIds(fileId,
|
||||
recategorizationRequest);
|
||||
|
||||
@ -255,6 +256,7 @@ public class ManualRedactionService {
|
||||
|
||||
response.add(ManualAddResponse.builder().annotationId(recategorizationRequest.getAnnotationId()).commentId(commentId).build());
|
||||
}
|
||||
|
||||
reprocess(dossierId, fileId);
|
||||
|
||||
fileStatusPersistenceService.setLastManualChangeDate(fileId, OffsetDateTime.now());
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user