RED-9474 - Revert only local manual changes for an annotation #590
@ -71,12 +71,13 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
public void undo(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<String> annotationIds,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) {
|
||||
@RequestParam(value = "includeOnlyUnprocessed", required = false, defaultValue = FALSE) boolean includeOnlyUnprocessed,
|
||||
@RequestParam(value = "includeOnlyLocal", required = false, defaultValue = FALSE) boolean includeOnlyLocal) {
|
||||
|
||||
accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsApprover(dossierId);
|
||||
manualRedactionUndoService.undo(dossierId, fileId, annotationIds, includeUnprocessed);
|
||||
manualRedactionUndoService.undo(dossierId, fileId, annotationIds, includeOnlyUnprocessed, includeOnlyLocal);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.external.resource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
@ -15,7 +14,6 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationComments;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactionResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequestModel;
|
||||
@ -57,7 +55,8 @@ public interface ManualRedactionResource {
|
||||
void undo(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<String> annotationIds,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed);
|
||||
@RequestParam(value = "includeOnlyUnprocessed", required = false, defaultValue = FALSE) boolean includeOnlyUnprocessed,
|
||||
@RequestParam(value = "includeOnlyLocal", required = false, defaultValue = FALSE) boolean includeOnlyLocal);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
|
||||
@ -5,7 +5,6 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.BaseAnnotation;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRedactionEntry;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
@ -23,6 +22,8 @@ public class ManualChangesQueryOptions {
|
||||
private boolean includeDeletions = false;
|
||||
@Builder.Default
|
||||
private Set<Class<? extends BaseAnnotation>> excludedClasses = Collections.emptySet();
|
||||
@Builder.Default
|
||||
private List<String> annotationIds = Collections.emptyList();
|
||||
|
||||
|
||||
public static ManualChangesQueryOptions allWithoutDeleted() {
|
||||
@ -42,6 +43,11 @@ public class ManualChangesQueryOptions {
|
||||
return ManualChangesQueryOptions.builder().includeDeletions(false).includeDictChanges(true).includeOnlyUnprocessed(true).build();
|
||||
}
|
||||
|
||||
public static ManualChangesQueryOptions unprocessedOnlyForIds(List<String> annotationIds) {
|
||||
|
||||
return ManualChangesQueryOptions.builder().includeDeletions(false).includeDictChanges(true).includeOnlyUnprocessed(true).annotationIds(annotationIds).build();
|
||||
}
|
||||
|
||||
|
||||
public static ManualChangesQueryOptions localChangesOnly() {
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ public class EntityLogMongoWrapperService {
|
||||
List<EntityLogEntry> entityLogEntries = entityLogMongoService.findEntityLogEntriesByIds(dossierId, fileId, ids);
|
||||
if (includeUnprocessed) {
|
||||
DossierEntity dossier = dossierService.getDossierById(dossierId);
|
||||
ManualRedactions unprocessedManualRedactions = manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.unprocessedOnly(), ids);
|
||||
ManualRedactions unprocessedManualRedactions = manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.unprocessedOnlyForIds(ids));
|
||||
entityLogEntries = entityLogMergeService.mergeEntityLogEntries(unprocessedManualRedactions, entityLogEntries.stream().map(EntityLogEntry::getId).toList(), dossier, fileId);
|
||||
}
|
||||
return entityLogEntries;
|
||||
|
||||
@ -4,9 +4,7 @@ import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicC
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -49,11 +47,11 @@ public class ManualRedactionProviderService {
|
||||
private final ResizeRedactionPersistenceService resizeRedactionPersistenceService;
|
||||
|
||||
|
||||
public void convertUnprocessedAddToDictionariesToLocalChanges(String fileId) {
|
||||
|
||||
public void convertUnprocessedAddToDictionariesToLocalChanges(String fileId){
|
||||
var unprocessedManualAdds = addRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, ManualChangesQueryOptions.unprocessedOnly());
|
||||
for (var unprocessedManualAdd : unprocessedManualAdds){
|
||||
if (unprocessedManualAdd.isAddToDictionary() || unprocessedManualAdd.isAddToAllDossiers()){
|
||||
for (var unprocessedManualAdd : unprocessedManualAdds) {
|
||||
if (unprocessedManualAdd.isAddToDictionary() || unprocessedManualAdd.isAddToAllDossiers()) {
|
||||
unprocessedManualAdd.setAddToDictionary(false);
|
||||
unprocessedManualAdd.setAddToAllDossiers(false);
|
||||
unprocessedManualAdd.setLegalBasis("");
|
||||
@ -65,12 +63,6 @@ public class ManualRedactionProviderService {
|
||||
|
||||
@Transactional
|
||||
public ManualRedactions getManualRedactions(String fileId, ManualChangesQueryOptions options) {
|
||||
return getManualRedactions(fileId, options, Collections.emptyList());
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public ManualRedactions getManualRedactions(String fileId, ManualChangesQueryOptions options, List<String> annotationIds) {
|
||||
|
||||
Set<ManualRedactionEntry> entriesToAdd;
|
||||
Set<IdRemoval> removals;
|
||||
@ -121,15 +113,6 @@ public class ManualRedactionProviderService {
|
||||
legalBasisChanges = Collections.emptySet();
|
||||
}
|
||||
|
||||
if(!annotationIds.isEmpty()){
|
||||
return new ManualRedactions(removals.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet()),
|
||||
entriesToAdd.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet()),
|
||||
forceRedactions.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet()),
|
||||
recategorizations.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet()),
|
||||
legalBasisChanges.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet()),
|
||||
resizeRedactions.stream().filter(r -> annotationIds.contains(r.getAnnotationId())).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
return new ManualRedactions(removals, entriesToAdd, forceRedactions, recategorizations, legalBasisChanges, resizeRedactions);
|
||||
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRecategorizationEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity;
|
||||
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.model.ManualChangesQueryOptions;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService;
|
||||
@ -72,31 +73,56 @@ public class ManualRedactionUndoService {
|
||||
|
||||
|
||||
@Transactional
|
||||
public void undo(String dossierId, String fileId, Set<String> annotationIds, boolean includeUnprocessed) {
|
||||
public void undo(String dossierId, String fileId, Set<String> annotationIds, boolean includeOnlyUnprocessed, boolean includeOnlyLocal) {
|
||||
|
||||
// undo the latest manual redaction for each annotationId
|
||||
ManualRedactions manualRedactions = getManualRedactions(fileId);
|
||||
// undo the manual redaction for each annotationId
|
||||
ManualRedactions manualRedactions = getManualRedactions(fileId, includeOnlyUnprocessed, includeOnlyLocal, new ArrayList<>(annotationIds));
|
||||
|
||||
Map<String, ManualRedactionWrapperModel> manualRedactionWrappers = getLatestManualRedactionsForAnnotationIds(manualRedactions, annotationIds);
|
||||
Map<String, List<ManualRedactionWrapperModel>> manualRedactionWrappers = groupAndSortManualRedactionsForAnnotationIds(manualRedactions, annotationIds);
|
||||
|
||||
if (manualRedactionWrappers.isEmpty()) {
|
||||
throw new NotFoundException(String.format("ManualRedaction with annotationIds %s could not be found.", annotationIds));
|
||||
}
|
||||
|
||||
undoManualRedactionEntries(dossierId, fileId, manualRedactionWrappers);
|
||||
undoIdRemovals(dossierId, fileId, manualRedactionWrappers);
|
||||
undoForceRedactions(dossierId, fileId, manualRedactionWrappers);
|
||||
undoRecategorization(dossierId, fileId, manualRedactionWrappers, includeUnprocessed);
|
||||
undoLegalBasisChange(dossierId, fileId, manualRedactionWrappers);
|
||||
undoResize(dossierId, fileId, manualRedactionWrappers);
|
||||
for (String annotationId : manualRedactionWrappers.keySet()) {
|
||||
manualRedactionWrappers.get(annotationId)
|
||||
.stream()
|
||||
.forEach(manualChange -> {
|
||||
if (manualChange.getItem() instanceof ManualRedactionEntry) {
|
||||
undoManualRedactionEntry(dossierId, fileId, annotationId);
|
||||
} else if (manualChange.getItem() instanceof IdRemoval) {
|
||||
undoIdRemoval(dossierId, fileId, annotationId);
|
||||
} else if (manualChange.getItem() instanceof ManualResizeRedaction) {
|
||||
undoResizeEntry(dossierId, fileId, annotationId);
|
||||
} else if (manualChange.getItem() instanceof ManualLegalBasisChange) {
|
||||
undoLegalBasisChangeEntry(dossierId, fileId, annotationId);
|
||||
} else if (manualChange.getItem() instanceof ManualRecategorization) {
|
||||
undoRecategorizationEntry(dossierId, fileId, annotationId, includeOnlyUnprocessed);
|
||||
} else if (manualChange.getItem() instanceof ManualForceRedaction) {
|
||||
undoForceRedactionEntry(dossierId, fileId, annotationId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
reprocess(dossierId, fileId);
|
||||
fileStatusPersistenceService.setLastManualChangeDate(fileId, OffsetDateTime.now());
|
||||
}
|
||||
|
||||
|
||||
private ManualRedactions getManualRedactions(String fileId) {
|
||||
private ManualRedactions getManualRedactions(String fileId, boolean includeOnlyUnprocessed, boolean includeOnlyLocal, List<String> annotationIds) {
|
||||
|
||||
return manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.allWithoutDeleted());
|
||||
var fileStatus = fileStatusService.getStatus(fileId);
|
||||
if (fileStatus.isExcludedFromAutomaticAnalysis() && !includeOnlyUnprocessed) { // analysis is disabled, only unprocessed changes can be reverted
|
||||
throw new BadRequestException("Only unprocessed manual redactions can be reverted. includeOnlyUnprocessed must be set to true");
|
||||
}
|
||||
|
||||
ManualChangesQueryOptions options = ManualChangesQueryOptions.builder()
|
||||
.includeDeletions(false)
|
||||
.includeDictChanges(!includeOnlyLocal)
|
||||
.includeOnlyUnprocessed(includeOnlyUnprocessed)
|
||||
.annotationIds(annotationIds)
|
||||
.build();
|
||||
return manualRedactionProviderService.getManualRedactions(fileId, options);
|
||||
}
|
||||
|
||||
|
||||
@ -106,236 +132,112 @@ public class ManualRedactionUndoService {
|
||||
}
|
||||
|
||||
|
||||
private void undoResize(String dossierId, String fileId, Map<String, ManualRedactionWrapperModel> manualRedactionWrappers) {
|
||||
|
||||
List<String> manualResizeRedactions = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualResizeRedaction)
|
||||
.map(ManualRedactionWrapperModel::getId)
|
||||
.toList();
|
||||
if (!manualResizeRedactions.isEmpty()) {
|
||||
deleteResizeRedaction(dossierId, fileId, manualResizeRedactions);
|
||||
manualResizeRedactions.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual resize redaction was done.")
|
||||
.details(Map.of(DOSSIER_ID,
|
||||
dossierId,
|
||||
FILE_ID,
|
||||
fileId,
|
||||
ANNOTATION_ID,
|
||||
annotationId))
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void deleteResizeRedaction(String dossierId, String fileId, List<String> annotationIds) {
|
||||
private void undoResizeEntry(String dossierId, String fileId, String annotationId) {
|
||||
|
||||
OffsetDateTime now = OffsetDateTime.now();
|
||||
for (var annotationId : annotationIds) {
|
||||
resizeRedactionPersistenceService.softDelete(fileId, annotationId, now);
|
||||
}
|
||||
resizeRedactionPersistenceService.softDelete(fileId, annotationId, now);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual resize redaction was done.")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
|
||||
.build());
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void undoLegalBasisChange(String dossierId, String fileId, Map<String, ManualRedactionWrapperModel> manualRedactionWrappers) {
|
||||
private void undoLegalBasisChangeEntry(String dossierId, String fileId, String annotationId) {
|
||||
|
||||
List<String> manualLegalBasisChanges = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualLegalBasisChange)
|
||||
.map(ManualRedactionWrapperModel::getId)
|
||||
.toList();
|
||||
if (!manualLegalBasisChanges.isEmpty()) {
|
||||
|
||||
deleteLegalBasisChange(dossierId, fileId, manualLegalBasisChanges);
|
||||
manualLegalBasisChanges.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of legal basis change was done.")
|
||||
.details(Map.of(DOSSIER_ID,
|
||||
dossierId,
|
||||
FILE_ID,
|
||||
fileId,
|
||||
ANNOTATION_ID,
|
||||
annotationId))
|
||||
.build()));
|
||||
}
|
||||
legalBasisChangePersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of legal basis change was done.")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
private void deleteLegalBasisChange(String dossierId, String fileId, List<String> annotationIds) {
|
||||
private void undoRecategorizationEntry(String dossierId, String fileId, String annotationId, boolean includeUnprocessed) {
|
||||
|
||||
for (var annotationId : annotationIds) {
|
||||
legalBasisChangePersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void undoRecategorization(String dossierId, String fileId, Map<String, ManualRedactionWrapperModel> manualRedactionWrappers, boolean includeUnprocessed) {
|
||||
|
||||
List<String> manualRecategorizations = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualRecategorization)
|
||||
.map(ManualRedactionWrapperModel::getId)
|
||||
.toList();
|
||||
if (!manualRecategorizations.isEmpty()) {
|
||||
|
||||
deleteRecategorization(dossierId, fileId, manualRecategorizations, includeUnprocessed);
|
||||
manualRecategorizations.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual recategorization was done.")
|
||||
.details(Map.of(DOSSIER_ID,
|
||||
dossierId,
|
||||
FILE_ID,
|
||||
fileId,
|
||||
ANNOTATION_ID,
|
||||
annotationId))
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void deleteRecategorization(String dossierId, String fileId, List<String> annotationIds, boolean includeUnprocessed) {
|
||||
|
||||
dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId, includeUnprocessed);
|
||||
|
||||
for (var annotationId : annotationIds) {
|
||||
ManualRecategorizationEntity recategorizationEntity = recategorizationPersistenceService.findRecategorization(fileId, annotationId);
|
||||
String originalValue = getEntityLogEntry(entityLog, annotationId).getValue();
|
||||
manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, recategorizationEntity.getTypeIdsOfDictionariesWithDelete());
|
||||
manualRedactionDictionaryUpdateHandler.revertAddToDictionary(originalValue,
|
||||
DictionaryEntryType.ENTRY,
|
||||
fileId,
|
||||
dossierId,
|
||||
recategorizationEntity.getTypeIdsOfDictionariesWithAdd());
|
||||
recategorizationEntity.setTypeIdsOfDictionariesWithAdd(Collections.emptySet());
|
||||
recategorizationEntity.setTypeIdsOfDictionariesWithDelete(Collections.emptySet());
|
||||
recategorizationEntity.setSoftDeletedTime(OffsetDateTime.now());
|
||||
recategorizationPersistenceService.saveAndFlush(recategorizationEntity);
|
||||
}
|
||||
ManualRecategorizationEntity recategorizationEntity = recategorizationPersistenceService.findRecategorization(fileId, annotationId);
|
||||
String originalValue = getEntityLogEntry(entityLog, annotationId).getValue();
|
||||
manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, recategorizationEntity.getTypeIdsOfDictionariesWithDelete());
|
||||
manualRedactionDictionaryUpdateHandler.revertAddToDictionary(originalValue,
|
||||
DictionaryEntryType.ENTRY,
|
||||
fileId,
|
||||
dossierId,
|
||||
recategorizationEntity.getTypeIdsOfDictionariesWithAdd());
|
||||
recategorizationEntity.setTypeIdsOfDictionariesWithAdd(Collections.emptySet());
|
||||
recategorizationEntity.setTypeIdsOfDictionariesWithDelete(Collections.emptySet());
|
||||
recategorizationEntity.setSoftDeletedTime(OffsetDateTime.now());
|
||||
recategorizationPersistenceService.saveAndFlush(recategorizationEntity);
|
||||
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual recategorization was done.")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
private void undoForceRedactions(String dossierId, String fileId, Map<String, ManualRedactionWrapperModel> manualRedactionWrappers) {
|
||||
|
||||
List<String> manualForceRedactions = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualForceRedaction)
|
||||
.map(ManualRedactionWrapperModel::getId)
|
||||
.toList();
|
||||
if (!manualForceRedactions.isEmpty()) {
|
||||
|
||||
deleteForceRedaction(dossierId, fileId, manualForceRedactions);
|
||||
manualForceRedactions.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual force redaction was done.")
|
||||
.details(Map.of(DOSSIER_ID,
|
||||
dossierId,
|
||||
FILE_ID,
|
||||
fileId,
|
||||
ANNOTATION_ID,
|
||||
annotationId))
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void deleteForceRedaction(String dossierId, String fileId, List<String> annotationIds) {
|
||||
private void undoForceRedactionEntry(String dossierId, String fileId, String annotationId) {
|
||||
|
||||
var now = OffsetDateTime.now();
|
||||
|
||||
for (var annotationId : annotationIds) {
|
||||
forceRedactionPersistenceService.softDelete(fileId, annotationId, now);
|
||||
}
|
||||
forceRedactionPersistenceService.softDelete(fileId, annotationId, now);
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual force redaction was done.")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
|
||||
.build());
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void undoIdRemovals(String dossierId, String fileId, Map<String, ManualRedactionWrapperModel> manualRedactionWrappers) {
|
||||
private void undoIdRemoval(String dossierId, String fileId, String annotationId) {
|
||||
|
||||
List<String> idRemovals = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof IdRemoval)
|
||||
.map(ManualRedactionWrapperModel::getId)
|
||||
.toList();
|
||||
if (!idRemovals.isEmpty()) {
|
||||
deleteRemoveRedaction(dossierId, fileId, idRemovals);
|
||||
idRemovals.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual remove redaction was done.")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void deleteRemoveRedaction(String dossierId, String fileId, List<String> annotationIds) {
|
||||
|
||||
dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId, true);
|
||||
|
||||
for (String annotationId : annotationIds) {
|
||||
IdRemovalEntity removeRedaction = removeRedactionPersistenceService.findRemoveRedaction(fileId, annotationId);
|
||||
String originalValue = getEntityLogEntry(entityLog, annotationId).getValue();
|
||||
boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, removeRedaction);
|
||||
removeRedactionPersistenceService.updateModifiedDictionaries(fileId, annotationId, dictionaryChanged, Collections.emptySet());
|
||||
removeRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
|
||||
IdRemovalEntity removeRedaction = removeRedactionPersistenceService.findRemoveRedaction(fileId, annotationId);
|
||||
String originalValue = getEntityLogEntry(entityLog, annotationId).getValue();
|
||||
boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, removeRedaction);
|
||||
removeRedactionPersistenceService.updateModifiedDictionaries(fileId, annotationId, dictionaryChanged, Collections.emptySet());
|
||||
removeRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
}
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual remove redaction was done.")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
|
||||
.build());
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void undoManualRedactionEntries(String dossierId, String fileId, Map<String, ManualRedactionWrapperModel> manualRedactionWrappers) {
|
||||
private void undoManualRedactionEntry(String dossierId, String fileId, String annotationId) {
|
||||
|
||||
List<String> manualRedactionEntries = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualRedactionEntry)
|
||||
.map(ManualRedactionWrapperModel::getId)
|
||||
.toList();
|
||||
if (!manualRedactionEntries.isEmpty()) {
|
||||
deleteAddRedaction(dossierId, fileId, manualRedactionEntries);
|
||||
manualRedactionEntries.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual add redaction was done.")
|
||||
.details(Map.of(DOSSIER_ID,
|
||||
dossierId,
|
||||
FILE_ID,
|
||||
fileId,
|
||||
ANNOTATION_ID,
|
||||
annotationId))
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
ManualRedactionEntryEntity addRedaction = addRedactionPersistenceService.findAddRedaction(fileId, annotationId);
|
||||
|
||||
boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertAddToDictionary(fileId, dossierId, addRedaction);
|
||||
addRedactionPersistenceService.updateModifiedDictionaries(fileId, annotationId, dictionaryChanged, null);
|
||||
addRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
|
||||
private void deleteAddRedaction(String dossierId, String fileId, List<String> annotationIds) {
|
||||
|
||||
var dossier = dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
|
||||
for (String annotationId : annotationIds) {
|
||||
|
||||
ManualRedactionEntryEntity addRedaction = addRedactionPersistenceService.findAddRedaction(fileId, annotationId);
|
||||
|
||||
boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertAddToDictionary(fileId, dossier.getId(), addRedaction);
|
||||
addRedactionPersistenceService.updateModifiedDictionaries(fileId, annotationId, dictionaryChanged, null);
|
||||
addRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
}
|
||||
auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual add redaction was done.")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
|
||||
.build());
|
||||
|
||||
}
|
||||
|
||||
@ -350,13 +252,13 @@ public class ManualRedactionUndoService {
|
||||
}
|
||||
|
||||
|
||||
private Map<String, ManualRedactionWrapperModel> getLatestManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set<String> annotationIds) {
|
||||
private Map<String, List<ManualRedactionWrapperModel>> groupAndSortManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set<String> annotationIds) {
|
||||
|
||||
Map<String, ManualRedactionWrapperModel> result = new HashMap<>();
|
||||
Map<String, List<ManualRedactionWrapperModel>> result = new HashMap<>();
|
||||
annotationIds.forEach(annotationId -> {
|
||||
var last = getLatestManualRedactionForAnnotationId(manualRedactions, annotationId);
|
||||
if (last != null) {
|
||||
result.put(annotationId, last);
|
||||
var manualRedactionsForId = getLatestManualRedactionForAnnotationId(manualRedactions, annotationId);
|
||||
if (manualRedactionsForId != null) {
|
||||
result.put(annotationId, manualRedactionsForId);
|
||||
}
|
||||
});
|
||||
|
||||
@ -364,7 +266,21 @@ public class ManualRedactionUndoService {
|
||||
}
|
||||
|
||||
|
||||
private ManualRedactionWrapperModel getLatestManualRedactionForAnnotationId(ManualRedactions manualRedactions, String annotationId) {
|
||||
private Map<String, ManualRedactionWrapperModel> getLatestManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set<String> annotationIds) {
|
||||
|
||||
Map<String, ManualRedactionWrapperModel> result = new HashMap<>();
|
||||
annotationIds.forEach(annotationId -> {
|
||||
var last = getLatestManualRedactionForAnnotationId(manualRedactions, annotationId);
|
||||
if (last != null) {
|
||||
result.put(annotationId, last.get(0));
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private List<ManualRedactionWrapperModel> getLatestManualRedactionForAnnotationId(ManualRedactions manualRedactions, String annotationId) {
|
||||
|
||||
final List<ManualRedactionWrapperModel> manualRedactionWrappers = new ArrayList<>();
|
||||
|
||||
@ -402,7 +318,7 @@ public class ManualRedactionUndoService {
|
||||
.sorted(Comparator.comparing(ManualRedactionWrapperModel::getDate, Comparator.nullsLast(Comparator.reverseOrder())))
|
||||
.toList();
|
||||
|
||||
return sortedManualRedactionWrappers.isEmpty() ? null : sortedManualRedactionWrappers.get(0);
|
||||
return sortedManualRedactionWrappers.isEmpty() ? null : sortedManualRedactionWrappers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -83,7 +83,14 @@ public class AddRedactionPersistenceService {
|
||||
@Transactional
|
||||
public List<ManualRedactionEntryEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
|
||||
|
||||
return manualRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
|
||||
if (options.getAnnotationIds().isEmpty()) {
|
||||
return manualRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
|
||||
}
|
||||
return manualRedactionRepository.findByFileIdAndOptionsAndAnnotationIds(fileId,
|
||||
options.isIncludeDeletions(),
|
||||
options.isIncludeOnlyUnprocessed(),
|
||||
options.isIncludeDictChanges(),
|
||||
options.getAnnotationIds());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -40,7 +40,10 @@ public class ForceRedactionPersistenceService {
|
||||
|
||||
public List<ManualForceRedactionEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
|
||||
|
||||
return forceRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed());
|
||||
if (options.getAnnotationIds().isEmpty()) {
|
||||
return forceRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed());
|
||||
}
|
||||
return forceRedactionRepository.findByFileIdAndOptionsAndAnnotationIds(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.getAnnotationIds());
|
||||
}
|
||||
|
||||
public int softDeleteByFileIds(List<String> fileIds, OffsetDateTime softDeletionTime) {
|
||||
|
||||
@ -81,7 +81,10 @@ public class LegalBasisChangePersistenceService {
|
||||
|
||||
public List<ManualLegalBasisChangeEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
|
||||
|
||||
return legalBasisChangeRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed());
|
||||
if (options.getAnnotationIds().isEmpty()) {
|
||||
return legalBasisChangeRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed());
|
||||
}
|
||||
return legalBasisChangeRepository.findByFileIdAndOptionsAndAnnotationIds(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.getAnnotationIds());
|
||||
}
|
||||
|
||||
public int softDeleteByFileIds(List<String> fileIds, OffsetDateTime softDeletionTime) {
|
||||
|
||||
@ -89,7 +89,10 @@ public class RecategorizationPersistenceService {
|
||||
|
||||
public List<ManualRecategorizationEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
|
||||
|
||||
return recategorizationRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
|
||||
if (options.getAnnotationIds().isEmpty()) {
|
||||
return recategorizationRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
|
||||
}
|
||||
return recategorizationRepository.findByFileIdAndOptionsAndAnnotationIds(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges(), options.getAnnotationIds());
|
||||
}
|
||||
|
||||
public int softDeleteByFileIds(List<String> fileIds, OffsetDateTime softDeletionTime) {
|
||||
|
||||
@ -49,7 +49,10 @@ public class RemoveRedactionPersistenceService {
|
||||
|
||||
public List<IdRemovalEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
|
||||
|
||||
return removeRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
|
||||
if (options.getAnnotationIds().isEmpty()) {
|
||||
return removeRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
|
||||
}
|
||||
return removeRedactionRepository.findByFileIdAndOptionsAndAnnotationIds(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges(), options.getAnnotationIds());
|
||||
}
|
||||
|
||||
public int softDeleteByFileIds(List<String> fileIds, OffsetDateTime softDeletionTime) {
|
||||
|
||||
@ -101,7 +101,10 @@ public class ResizeRedactionPersistenceService {
|
||||
|
||||
public List<ManualResizeRedactionEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
|
||||
|
||||
return resizeRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
|
||||
if (options.getAnnotationIds().isEmpty()) {
|
||||
return resizeRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
|
||||
}
|
||||
return resizeRedactionRepository.findByFileIdAndOptionsAndAnnotationIds(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges(), options.getAnnotationIds());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -48,6 +48,20 @@ public interface ForceRedactionRepository extends JpaRepository<ManualForceRedac
|
||||
@Param("unprocessed") boolean unprocessed);
|
||||
|
||||
|
||||
@Query("""
|
||||
select m
|
||||
from ManualForceRedactionEntity m
|
||||
where m.id.fileId = :fileId
|
||||
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
|
||||
and (:includeDeletions = true or m.softDeletedTime is null)
|
||||
and m.id.annotationId in (:annotationIds)
|
||||
""")
|
||||
List<ManualForceRedactionEntity> findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId,
|
||||
@Param("includeDeletions") boolean includeDeletions,
|
||||
@Param("unprocessed") boolean unprocessed,
|
||||
@Param("annotationIds") List<String> annotationIds);
|
||||
|
||||
|
||||
@Modifying
|
||||
@Query("update ManualForceRedactionEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null")
|
||||
int softDeleteByFileIds(@Param("fileIds") List<String> fileIds, @Param("softDeletedTime") OffsetDateTime softDeletedTime);
|
||||
|
||||
@ -47,6 +47,19 @@ public interface LegalBasisChangeRepository extends JpaRepository<ManualLegalBas
|
||||
@Param("includeDeletions") boolean includeDeletions,
|
||||
@Param("unprocessed") boolean unprocessed);
|
||||
|
||||
@Query("""
|
||||
select m
|
||||
from ManualLegalBasisChangeEntity m
|
||||
where m.id.fileId = :fileId
|
||||
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
|
||||
and (:includeDeletions = true or m.softDeletedTime is null)
|
||||
and m.id.annotationId in (:annotationIds)
|
||||
""")
|
||||
List<ManualLegalBasisChangeEntity> findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId,
|
||||
@Param("includeDeletions") boolean includeDeletions,
|
||||
@Param("unprocessed") boolean unprocessed,
|
||||
@Param("annotationIds") List<String> annotationIds);
|
||||
|
||||
|
||||
@Modifying
|
||||
@Query("update ManualLegalBasisChangeEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null")
|
||||
|
||||
@ -51,6 +51,21 @@ public interface ManualRedactionRepository extends JpaRepository<ManualRedaction
|
||||
@Param("unprocessed") boolean unprocessed,
|
||||
@Param("includeDictChanges") boolean includeDictChanges);
|
||||
|
||||
@Query("""
|
||||
select m
|
||||
from ManualRedactionEntryEntity m
|
||||
where m.id.fileId = :fileId
|
||||
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
|
||||
and (:includeDeletions = true or m.softDeletedTime is null)
|
||||
and (:includeDictChanges = true or (m.addToDictionary = false and m.addToAllDossiers = false))
|
||||
and m.id.annotationId in (:annotationIds)
|
||||
""")
|
||||
List<ManualRedactionEntryEntity> findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId,
|
||||
@Param("includeDeletions") boolean includeDeletions,
|
||||
@Param("unprocessed") boolean unprocessed,
|
||||
@Param("includeDictChanges") boolean includeDictChanges,
|
||||
@Param("annotationIds") List<String> annotationIds);
|
||||
|
||||
@Modifying
|
||||
@Query("update ManualRedactionEntryEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null")
|
||||
int softDeleteByFileIds(@Param("fileIds") List<String> fileIds,
|
||||
|
||||
@ -49,6 +49,23 @@ public interface RecategorizationRepository extends JpaRepository<ManualRecatego
|
||||
@Param("unprocessed") boolean unprocessed,
|
||||
@Param("includeDictChanges") boolean includeDictChanges);
|
||||
|
||||
|
||||
@Query("""
|
||||
select m
|
||||
from ManualRecategorizationEntity m
|
||||
where m.id.fileId = :fileId
|
||||
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
|
||||
and (:includeDeletions = true or m.softDeletedTime is null)
|
||||
and (:includeDictChanges = true or (m.addToDictionary = false and m.addToAllDossiers = false))
|
||||
and m.id.annotationId in (:annotationIds)
|
||||
""")
|
||||
List<ManualRecategorizationEntity> findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId,
|
||||
@Param("includeDeletions") boolean includeDeletions,
|
||||
@Param("unprocessed") boolean unprocessed,
|
||||
@Param("includeDictChanges") boolean includeDictChanges,
|
||||
@Param("annotationIds") List<String> annotationIds);
|
||||
|
||||
|
||||
@Modifying
|
||||
@Query("update ManualRecategorizationEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null")
|
||||
int softDeleteByFileIds(@Param("fileIds") List<String> fileIds,
|
||||
|
||||
@ -49,6 +49,21 @@ public interface RemoveRedactionRepository extends JpaRepository<IdRemovalEntity
|
||||
@Param("unprocessed") boolean unprocessed,
|
||||
@Param("includeDictChanges") boolean includeDictChanges);
|
||||
|
||||
@Query("""
|
||||
select m
|
||||
from IdRemovalEntity m
|
||||
where m.id.fileId = :fileId
|
||||
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
|
||||
and (:includeDeletions = true or m.softDeletedTime is null)
|
||||
and (:includeDictChanges = true or (m.removeFromDictionary = false and m.removeFromAllDossiers = false))
|
||||
and m.id.annotationId in (:annotationIds)
|
||||
""")
|
||||
List<IdRemovalEntity> findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId,
|
||||
@Param("includeDeletions") boolean includeDeletions,
|
||||
@Param("unprocessed") boolean unprocessed,
|
||||
@Param("includeDictChanges") boolean includeDictChanges,
|
||||
@Param("annotationIds") List<String> annotationIds);
|
||||
|
||||
@Modifying
|
||||
@Query("update IdRemovalEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null")
|
||||
int softDeleteByFileIds(@Param("fileIds") List<String> fileIds,
|
||||
|
||||
@ -57,6 +57,23 @@ public interface ResizeRedactionRepository extends JpaRepository<ManualResizeRed
|
||||
@Param("unprocessed") boolean unprocessed,
|
||||
@Param("includeDictChanges") boolean includeDictChanges);
|
||||
|
||||
|
||||
@Query("""
|
||||
select m
|
||||
from ManualResizeRedactionEntity m
|
||||
where m.id.fileId = :fileId
|
||||
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
|
||||
and (:includeDeletions = true or m.softDeletedTime is null)
|
||||
and (:includeDictChanges = true or (m.updateDictionary = false and m.addToAllDossiers = false))
|
||||
and m.id.annotationId in (:annotationIds)
|
||||
""")
|
||||
List<ManualResizeRedactionEntity> findByFileIdAndOptionsAndAnnotationIds(@Param("fileId") String fileId,
|
||||
@Param("includeDeletions") boolean includeDeletions,
|
||||
@Param("unprocessed") boolean unprocessed,
|
||||
@Param("includeDictChanges") boolean includeDictChanges,
|
||||
@Param("annotationIds") List<String> annotationIds);
|
||||
|
||||
|
||||
@Modifying
|
||||
@Query("update ManualResizeRedactionEntity m set m.softDeletedTime = :softDeletedTime where m.id.fileId in (:fileIds) and m.softDeletedTime is null")
|
||||
int softDeleteByFileIds(@Param("fileIds") List<String> fileIds,
|
||||
|
||||
@ -366,7 +366,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId());
|
||||
assertThat(dossierDictionary.getEntries()).isEmpty();
|
||||
|
||||
manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of("AnnotationId"), false);
|
||||
manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of("AnnotationId"), false, false);
|
||||
|
||||
dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker", "Darth Vader");
|
||||
@ -1244,7 +1244,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId());
|
||||
assertThat(dossierDictionary2.getEntries()).isEmpty();
|
||||
|
||||
manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId), false);
|
||||
manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId), false, false);
|
||||
|
||||
dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader);
|
||||
@ -1258,6 +1258,131 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testManualRecategorizeAndUndoOnlyManualChanges() {
|
||||
|
||||
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
|
||||
var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate);
|
||||
var file = fileTesterAndProvider.testAndProvideFile(dossier);
|
||||
|
||||
var type = typeProvider.testAndProvideType(dossierTemplate);
|
||||
var type2 = typeProvider.testAndProvideType(dossierTemplate, dossier, "test2", false, 66);
|
||||
|
||||
var entries = new ArrayList<String>();
|
||||
|
||||
var lukeSkywalker = "Luke Skywalker";
|
||||
var darthVader = "Darth Vader";
|
||||
entries.add(lukeSkywalker);
|
||||
entries.add(darthVader);
|
||||
dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), entries, false, null, DictionaryEntryType.ENTRY);
|
||||
|
||||
dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of(lukeSkywalker), false, dossier.getId(), DictionaryEntryType.ENTRY);
|
||||
|
||||
Dictionary dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader);
|
||||
Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId());
|
||||
assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker);
|
||||
|
||||
Dictionary dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary2.getEntries()).isEmpty();
|
||||
Dictionary dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId());
|
||||
assertThat(dossierDictionary2.getEntries()).isEmpty();
|
||||
|
||||
var annotationId = "AnnotationId";
|
||||
var entityLog = new EntityLog(1,
|
||||
1,
|
||||
List.of(EntityLogEntry.builder()
|
||||
.id(annotationId)
|
||||
.type(type.getType())
|
||||
.value(lukeSkywalker)
|
||||
.dictionaryEntry(true)
|
||||
.entryType(EntryType.ENTITY)
|
||||
.state(EntryState.APPLIED)
|
||||
.build()),
|
||||
null,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
fileManagementStorageService.saveEntityLog(dossier.getId(), file.getId(), entityLog);
|
||||
|
||||
when(entityLogService.getEntityLog(any(), any(), anyBoolean())).thenReturn(entityLog);
|
||||
|
||||
manualRedactionClient.recategorizeBulk(dossier.getId(),
|
||||
file.getId(),
|
||||
Set.of(RecategorizationRequestModel.builder()
|
||||
.type(type2.getType())
|
||||
.annotationId(annotationId)
|
||||
.addToDictionary(true)
|
||||
.addToAllDossiers(true)
|
||||
.legalBasis("")
|
||||
.section("section")
|
||||
.value(lukeSkywalker)
|
||||
.build()),
|
||||
false);
|
||||
|
||||
dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(darthVader);
|
||||
dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId());
|
||||
assertThat(dossierDictionary.getEntries()).isEmpty();
|
||||
|
||||
dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary2.getEntries()).containsExactlyInAnyOrder(lukeSkywalker);
|
||||
dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId());
|
||||
assertThat(dossierDictionary2.getEntries()).isEmpty();
|
||||
|
||||
// try to undo only local changes, but there are none for the requested annotationId
|
||||
String errorMessage = assertThrows(FeignException.NotFound.class,
|
||||
() -> manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId), false, true)).getMessage();
|
||||
assertTrue(errorMessage.contains("ManualRedaction with annotationIds [AnnotationId] could not be found"));
|
||||
|
||||
dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(darthVader);
|
||||
dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId());
|
||||
assertThat(dossierDictionary.getEntries()).isEmpty();
|
||||
|
||||
dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary2.getEntries()).containsExactlyInAnyOrder(lukeSkywalker);
|
||||
dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId());
|
||||
assertThat(dossierDictionary2.getEntries()).isEmpty();
|
||||
|
||||
var resizeRedactionRequestModel = ResizeRedactionRequestModel.builder()
|
||||
.annotationId(annotationId)
|
||||
.value(lukeSkywalker + " resized")
|
||||
.updateDictionary(false)
|
||||
.addToAllDossiers(false)
|
||||
.positions(List.of(Rectangle.builder().page(1).height(1).width(2).topLeftX(1).topLeftY(1).build()))
|
||||
.build();
|
||||
|
||||
ManualRedactionResponse response = manualRedactionClient.resizeRedactionBulk(dossier.getId(), file.getId(), Set.of(resizeRedactionRequestModel), false);
|
||||
|
||||
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
|
||||
|
||||
assertEquals(allManualRedactions.getResizeRedactions().size(), 1);
|
||||
assertEquals(allManualRedactions.getEntriesToAdd().size(), 1);
|
||||
assertEquals(allManualRedactions.getRecategorizations().size(), 1);
|
||||
var entryToResize = allManualRedactions.getResizeRedactions()
|
||||
.stream()
|
||||
.findFirst()
|
||||
.get();
|
||||
var entryToAdd = allManualRedactions.getEntriesToAdd()
|
||||
.stream()
|
||||
.findFirst()
|
||||
.get();
|
||||
assertFalse(entryToAdd.isAddToDictionary());
|
||||
assertFalse(entryToAdd.isAddToDossierDictionary());
|
||||
assertEquals(entryToAdd.getAnnotationId(), entryToResize.getAnnotationId());
|
||||
|
||||
manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId, entryToResize.getAnnotationId()), false, true);
|
||||
|
||||
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
|
||||
|
||||
assertEquals(allManualRedactions.getResizeRedactions().size(), 0);
|
||||
assertEquals(allManualRedactions.getEntriesToAdd().size(), 0);
|
||||
assertEquals(allManualRedactions.getRecategorizations().size(), 1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testManualRecategorizeAndUndoDossierLevelOnly() {
|
||||
|
||||
@ -1330,7 +1455,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId());
|
||||
assertThat(dossierDictionary2.getEntries()).containsExactlyInAnyOrder(lukeSkywalker);
|
||||
|
||||
manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId), false);
|
||||
manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId), false, false);
|
||||
|
||||
dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary.getEntries()).isEmpty();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user