RED-7317: Keep user-edited paragraph/location when recategorizing entity #101
@ -8,8 +8,6 @@ import static com.iqser.red.service.persistence.management.v1.processor.roles.Ac
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -20,93 +18,53 @@ import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ManualRedactionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.CommentService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionUndoService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments;
|
||||
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.ManualRedactions;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualImageRecategorization;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange;
|
||||
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.RecategorizationRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ImageRecategorizationRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ManualRedactionWrapper;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequest;
|
||||
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.manual.AddCommentRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel;
|
||||
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.ResizeRedactionRequestModel;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class ManualRedactionController implements ManualRedactionResource {
|
||||
|
||||
private static final String FILE_ID = "fileId";
|
||||
private static final String DOSSIER_ID = "dossierId";
|
||||
private static final String ANNOTATION_ID = "annotationId";
|
||||
private final ManualRedactionService manualRedactionService;
|
||||
private final DossierManagementService dossierManagementService;
|
||||
private final AuditPersistenceService auditPersistenceService;
|
||||
private final AccessControlService accessControlService;
|
||||
|
||||
|
||||
|
||||
private ManualRedactionWrapper getLatestManualRedactionForAnnotationId(ManualRedactions manualRedactions, String annotationId) {
|
||||
|
||||
final List<ManualRedactionWrapper> manualRedactionWrappers = new ArrayList<>();
|
||||
|
||||
manualRedactions.getEntriesToAdd()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
manualRedactions.getImageRecategorization()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
manualRedactions.getIdsToRemove()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
manualRedactions.getForceRedactions()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
manualRedactions.getLegalBasisChanges()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
manualRedactions.getResizeRedactions()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
var sortedManualRedactionWrappers = manualRedactionWrappers.stream()
|
||||
.sorted(Comparator.comparing(ManualRedactionWrapper::getDate, Comparator.nullsLast(Comparator.reverseOrder())))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return sortedManualRedactionWrappers.isEmpty() ? null : sortedManualRedactionWrappers.get(0);
|
||||
}
|
||||
final static String FILE_ID = "fileId";
|
||||
final static String DOSSIER_ID = "dossierId";
|
||||
final static String ANNOTATION_ID = "annotationId";
|
||||
ManualRedactionService manualRedactionService;
|
||||
ManualRedactionUndoService manualRedactionUndoService;
|
||||
DossierManagementService dossierManagementService;
|
||||
AuditPersistenceService auditPersistenceService;
|
||||
AccessControlService accessControlService;
|
||||
CommentService commentService;
|
||||
|
||||
|
||||
@Override
|
||||
@ -115,129 +73,8 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsApprover(dossierId);
|
||||
manualRedactionUndoService.undo(dossierId, fileId, annotationIds);
|
||||
|
||||
ManualRedactions manualRedactions = manualRedactionService.getManualRedactions(fileId);
|
||||
|
||||
Map<String, ManualRedactionWrapper> manualRedactionWrappers = getLatestManualRedactionsForAnnotationIds(manualRedactions, annotationIds);
|
||||
|
||||
if (manualRedactionWrappers.isEmpty()) {
|
||||
throw new NotFoundException(String.format("ManualRedaction with annotationIds %s could not be found.", annotationIds));
|
||||
}
|
||||
|
||||
List<String> manualRedactionEntries = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualRedactionEntry)
|
||||
.map(ManualRedactionWrapper::getId)
|
||||
.collect(Collectors.toList());
|
||||
if (!manualRedactionEntries.isEmpty()) {
|
||||
manualRedactionService.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()));
|
||||
}
|
||||
|
||||
List<String> idRemovals = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof IdRemoval)
|
||||
.map(ManualRedactionWrapper::getId)
|
||||
.collect(Collectors.toList());
|
||||
if (!idRemovals.isEmpty()) {
|
||||
|
||||
manualRedactionService.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()));
|
||||
}
|
||||
|
||||
List<String> manualForceRedactions = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualForceRedaction)
|
||||
.map(ManualRedactionWrapper::getId)
|
||||
.collect(Collectors.toList());
|
||||
if (!manualForceRedactions.isEmpty()) {
|
||||
|
||||
manualRedactionService.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()));
|
||||
}
|
||||
|
||||
List<String> manualImageRecategorizations = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualImageRecategorization)
|
||||
.map(ManualRedactionWrapper::getId)
|
||||
.collect(Collectors.toList());
|
||||
if (!manualImageRecategorizations.isEmpty()) {
|
||||
|
||||
manualRedactionService.deleteImageRecategorization(dossierId, fileId, manualImageRecategorizations);
|
||||
manualImageRecategorizations.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual image recategorization was done.")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
|
||||
.build()));
|
||||
}
|
||||
|
||||
List<String> manualLegalBasisChanges = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualLegalBasisChange)
|
||||
.map(ManualRedactionWrapper::getId)
|
||||
.collect(Collectors.toList());
|
||||
if (!manualLegalBasisChanges.isEmpty()) {
|
||||
|
||||
manualRedactionService.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()));
|
||||
}
|
||||
|
||||
List<String> manualResizeRedactions = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualResizeRedaction)
|
||||
.map(ManualRedactionWrapper::getId)
|
||||
.collect(Collectors.toList());
|
||||
if (!manualResizeRedactions.isEmpty()) {
|
||||
|
||||
manualRedactionService.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 Map<String, ManualRedactionWrapper> getLatestManualRedactionsForAnnotationIds(ManualRedactions manualRedactions, Set<String> annotationIds) {
|
||||
|
||||
Map<String, ManualRedactionWrapper> result = new HashMap<>();
|
||||
annotationIds.forEach(annotationId -> {
|
||||
var last = getLatestManualRedactionForAnnotationId(manualRedactions, annotationId);
|
||||
if (last != null) {
|
||||
result.put(annotationId, last);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -258,7 +95,7 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
.message("Comment was removed.")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
|
||||
.build());
|
||||
manualRedactionService.deleteComment(fileId, List.of(Long.valueOf(commentId)));
|
||||
commentService.deleteComment(dossierId, fileId, List.of(Long.valueOf(commentId)));
|
||||
|
||||
}
|
||||
|
||||
@ -271,17 +108,26 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')")
|
||||
public Comments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
|
||||
|
||||
return commentService.getComments(fileId);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + ADD_COMMENT + "')")
|
||||
public CommentResponse addComment(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@PathVariable(ANNOTATION_ID) String annotationId,
|
||||
@RequestBody AddCommentRequest addCommentRequest) {
|
||||
@RequestBody AddCommentRequestModel addCommentRequest) {
|
||||
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId);
|
||||
|
||||
var response = manualRedactionService.addComment(fileId,
|
||||
var response = commentService.addComment(dossierId,
|
||||
fileId,
|
||||
annotationId,
|
||||
CommentRequest.builder().user(KeycloakSecurity.getUserId()).text(addCommentRequest.getText()).build());
|
||||
|
||||
@ -301,41 +147,38 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> addRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<AddRedactionRequest> addRedactionRequests) {
|
||||
@RequestBody Set<AddRedactionRequestModel> addRedactionRequests) {
|
||||
|
||||
var dossier = dossierManagementService.getDossierById(dossierId, false, false);
|
||||
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
if(addRedactionRequests.stream().anyMatch(AddRedactionRequest::isAddToAllDossiers)){
|
||||
if (addRedactionRequests.stream().anyMatch(AddRedactionRequestModel::isAddToAllDossiers)) {
|
||||
accessControlService.verifyUserIsApprover(dossierId);
|
||||
} else {
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
}
|
||||
|
||||
List<com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest> requests = new ArrayList<>();
|
||||
List<AddRedactionRequest> requests = addRedactionRequests.stream()
|
||||
.map(addRedactionRequest -> AddRedactionRequest.builder()
|
||||
.value(addRedactionRequest.getValue())
|
||||
.legalBasis(addRedactionRequest.getLegalBasis())
|
||||
.user(KeycloakSecurity.getUserId())
|
||||
.dossierTemplateTypeId(toTypeId(addRedactionRequest.getType(), dossier.getDossierTemplateId()))
|
||||
.reason(addRedactionRequest.getReason())
|
||||
.addToDictionary(addRedactionRequest.isAddToDictionary())
|
||||
.status(AnnotationStatus.APPROVED)
|
||||
.comment(addRedactionRequest.getComment() != null ? addRedactionRequest.getComment().getText() : null)
|
||||
.section(addRedactionRequest.getSection())
|
||||
.rectangle(addRedactionRequest.isRectangle())
|
||||
.addToAllDossiers(addRedactionRequest.isAddToAllDossiers())
|
||||
.forceAddToDictionary(addRedactionRequest.isForceAddToDictionary())
|
||||
.positions(addRedactionRequest.getPositions())
|
||||
.sourceId(addRedactionRequest.getSourceId())
|
||||
.dossierId(dossierId)
|
||||
.dictionaryEntryType(addRedactionRequest.getDictionaryEntryType())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
for (var addRedactionRequest : addRedactionRequests) {
|
||||
|
||||
var addRedactionRequestBuilder = com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest.builder()
|
||||
.value(addRedactionRequest.getValue())
|
||||
.legalBasis(addRedactionRequest.getLegalBasis())
|
||||
.user(KeycloakSecurity.getUserId())
|
||||
.dossierTemplateTypeId(toTypeId(addRedactionRequest.getType(), dossier.getDossierTemplateId()))
|
||||
.reason(addRedactionRequest.getReason())
|
||||
.addToDictionary(addRedactionRequest.isAddToDictionary())
|
||||
.status(AnnotationStatus.APPROVED)
|
||||
.comment(addRedactionRequest.getComment() != null ? addRedactionRequest.getComment().getText() : null)
|
||||
.section(addRedactionRequest.getSection())
|
||||
.rectangle(addRedactionRequest.isRectangle())
|
||||
.addToAllDossiers(addRedactionRequest.isAddToAllDossiers())
|
||||
.forceAddToDictionary(addRedactionRequest.isForceAddToDictionary())
|
||||
.positions(addRedactionRequest.getPositions())
|
||||
.sourceId(addRedactionRequest.getSourceId())
|
||||
.dossierId(dossierId)
|
||||
.dictionaryEntryType(addRedactionRequest.getDictionaryEntryType());
|
||||
|
||||
requests.add(addRedactionRequestBuilder.build());
|
||||
}
|
||||
List<ManualAddResponse> responseList = manualRedactionService.addAddRedaction(dossierId, fileId, requests);
|
||||
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
@ -351,10 +194,10 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> removeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<RemoveRedactionRequest> removeRedactionRequests) {
|
||||
@RequestBody Set<RemoveRedactionRequestModel> removeRedactionRequests) {
|
||||
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
if(removeRedactionRequests.stream().anyMatch(RemoveRedactionRequest::isRemoveFromAllDossiers)){
|
||||
if (removeRedactionRequests.stream().anyMatch(RemoveRedactionRequestModel::isRemoveFromAllDossiers)) {
|
||||
accessControlService.verifyUserIsApprover(dossierId);
|
||||
} else {
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
@ -393,7 +236,7 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> forceRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<ForceRedactionRequest> forceRedactionRequests) {
|
||||
@RequestBody Set<ForceRedactionRequestModel> forceRedactionRequests) {
|
||||
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
@ -424,7 +267,7 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> legalBasisChangeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<LegalBasisChangeRequest> legalBasisChangeRequests) {
|
||||
@RequestBody Set<LegalBasisChangeRequestModel> legalBasisChangeRequests) {
|
||||
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
@ -456,31 +299,35 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
|
||||
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> recategorizeImageBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<ImageRecategorizationRequest> imageRecategorizationRequests) {
|
||||
public List<ManualAddResponse> recategorizeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<RecategorizationRequestModel> recategorizationRequests) {
|
||||
|
||||
var dossier = dossierManagementService.getDossierById(dossierId, false, false);
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
|
||||
List<com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ImageRecategorizationRequest> requests = imageRecategorizationRequests.stream()
|
||||
.map(imageRecategorizationRequest -> com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ImageRecategorizationRequest.builder()
|
||||
.annotationId(imageRecategorizationRequest.getAnnotationId())
|
||||
List<RecategorizationRequest> requests = recategorizationRequests.stream()
|
||||
.map(recategorizationRequest -> RecategorizationRequest.builder()
|
||||
.annotationId(recategorizationRequest.getAnnotationId())
|
||||
.user(KeycloakSecurity.getUserId())
|
||||
.status(AnnotationStatus.APPROVED)
|
||||
.typeId(toTypeId(imageRecategorizationRequest.getType(), dossier.getDossierTemplateId()))
|
||||
.comment(imageRecategorizationRequest.getComment())
|
||||
.dossierTemplateTypeId(toTypeId(recategorizationRequest.getType(), dossier.getDossierTemplateId()))
|
||||
.comment(recategorizationRequest.getComment())
|
||||
.dossierId(dossierId)
|
||||
.addToDictionary(recategorizationRequest.isAddToDictionary())
|
||||
.addToAllDossiers(recategorizationRequest.isAddToAllDossiers())
|
||||
.dictionaryEntryType(DictionaryEntryType.ENTRY)
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<ManualAddResponse> responseList = manualRedactionService.addImageRecategorization(dossierId, fileId, requests);
|
||||
List<ManualAddResponse> responseList = manualRedactionService.addRecategorization(dossierId, fileId, requests);
|
||||
|
||||
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Image was recategorized")
|
||||
.message("Entity was recategorized.")
|
||||
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
|
||||
.build()));
|
||||
|
||||
@ -491,7 +338,8 @@ public class ManualRedactionController implements ManualRedactionResource {
|
||||
@PreAuthorize("hasAuthority('" + DO_MANUAL_REDACTION + "')")
|
||||
public List<ManualAddResponse> resizeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<ResizeRedactionRequest> resizeRedactionRequests) {
|
||||
@RequestBody Set<ResizeRedactionRequestModel> resizeRedactionRequests) {
|
||||
|
||||
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
|
||||
accessControlService.verifyUserIsMemberOrApprover(dossierId);
|
||||
|
||||
|
||||
@ -52,7 +52,7 @@ public class RedactionLogController implements RedactionLogResource {
|
||||
@RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives) {
|
||||
|
||||
try {
|
||||
return redactionLogService.getRedactionLog(dossierId, fileId, excludedTypes, withManualRedactions, includeFalsePositives);
|
||||
return redactionLogService.getRedactionLog(dossierId, fileId, excludedTypes);
|
||||
} catch (FeignException e) {
|
||||
throw processFeignException(e);
|
||||
}
|
||||
|
||||
@ -13,15 +13,16 @@ import org.springframework.web.bind.annotation.RequestBody;
|
||||
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.Comments;
|
||||
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.ManualRedactions;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ImageRecategorizationRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel;
|
||||
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.ResizeRedactionRequestModel;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
@ -58,7 +59,7 @@ public interface ManualRedactionResource {
|
||||
CommentResponse addComment(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@PathVariable(ANNOTATION_ID) String annotationId,
|
||||
@RequestBody AddCommentRequest addCommentRequest);
|
||||
@RequestBody AddCommentRequestModel addCommentRequest);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NO_CONTENT)
|
||||
@ -77,7 +78,7 @@ public interface ManualRedactionResource {
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<ManualAddResponse> addRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<AddRedactionRequest> addRedactionRequest);
|
||||
@RequestBody Set<AddRedactionRequestModel> addRedactionRequest);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ -86,7 +87,7 @@ public interface ManualRedactionResource {
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<ManualAddResponse> removeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<RemoveRedactionRequest> removeRedactionRequests);
|
||||
@RequestBody Set<RemoveRedactionRequestModel> removeRedactionRequests);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ -95,7 +96,7 @@ public interface ManualRedactionResource {
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<ManualAddResponse> forceRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<ForceRedactionRequest> forceRedactionRequests);
|
||||
@RequestBody Set<ForceRedactionRequestModel> forceRedactionRequests);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ -104,16 +105,16 @@ public interface ManualRedactionResource {
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<ManualAddResponse> legalBasisChangeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<LegalBasisChangeRequest> legalBasisChangeRequests);
|
||||
@RequestBody Set<LegalBasisChangeRequestModel> legalBasisChangeRequests);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@PostMapping(value = MANUAL_REDACTION_REST_PATH + "/bulk/redaction/recategorize" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Recategorizes the images list", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<ManualAddResponse> recategorizeImageBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<ImageRecategorizationRequest> imageRecategorizationRequests);
|
||||
List<ManualAddResponse> recategorizeBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<RecategorizationRequestModel> recategorizationRequests);
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@ -122,7 +123,7 @@ public interface ManualRedactionResource {
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
List<ManualAddResponse> resizeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestBody Set<ResizeRedactionRequest> resizeRedactionRequests);
|
||||
@RequestBody Set<ResizeRedactionRequestModel> resizeRedactionRequests);
|
||||
|
||||
|
||||
|
||||
@ -132,4 +133,12 @@ public interface ManualRedactionResource {
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
|
||||
|
||||
|
||||
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
@GetMapping(value = MANUAL_REDACTION_REST_PATH + "/comments" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Returns the comments for a specific file", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
|
||||
Comments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
|
||||
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ public class RedactionLogInternalController implements RedactionLogResource {
|
||||
@RequestParam(value = "withManualRedactions", required = false, defaultValue = "true") boolean withManualRedactions,
|
||||
@RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives) {
|
||||
|
||||
return redactionLogService.getRedactionLog(dossierId, fileId, excludedTypes, withManualRedactions, includeFalsePositives);
|
||||
return redactionLogService.getRedactionLog(dossierId, fileId, excludedTypes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,18 +1,24 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.entity.annotations;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
|
||||
|
||||
import jakarta.persistence.CollectionTable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.ElementCollection;
|
||||
import jakarta.persistence.EmbeddedId;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
@ -43,8 +49,22 @@ public class ManualImageRecategorizationEntity implements IBaseAnnotation {
|
||||
private OffsetDateTime softDeletedTime;
|
||||
@Column
|
||||
private int page;
|
||||
@Column
|
||||
private boolean addToDictionary;
|
||||
@Column
|
||||
private boolean addToAllDossiers;
|
||||
|
||||
@ManyToOne
|
||||
private FileEntity fileStatus;
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(name = "manual_recategorization_type_ids_of_dictionaries_with_add")
|
||||
@Fetch(value = FetchMode.SUBSELECT)
|
||||
private Set<String> typeIdsOfDictionariesWithAdd = new HashSet<>();
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(name = "manual_recategorization_type_ids_of_dictionaries_with_delete")
|
||||
@Fetch(value = FetchMode.SUBSELECT)
|
||||
private Set<String> typeIdsOfDictionariesWithDelete = new HashSet<>();
|
||||
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import org.springframework.stereotype.Service;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.migration.Migration;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ManualRedactionProviderService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService;
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.migration.Migration;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ManualRedactionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService;
|
||||
|
||||
@ -36,7 +36,7 @@ public class AnalysisFlagsCalculationService {
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
var file = fileStatusPersistenceService.getStatus(fileId);
|
||||
var redactionLog = redactionLogService.getRedactionLog(dossierId, fileId, true, false);
|
||||
var redactionLog = redactionLogService.getRedactionLog(dossierId, fileId);
|
||||
|
||||
var viewedPagesForCurrentAssignee = viewedPagesPersistenceService.findViewedPages(fileId, file.getAssignee());
|
||||
|
||||
|
||||
@ -0,0 +1,128 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.CommentEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.CommentPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogComment;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class CommentService {
|
||||
|
||||
CommentPersistenceService commentPersistenceService;
|
||||
FileStatusPersistenceService fileStatusPersistenceService;
|
||||
FileStatusService fileStatusService;
|
||||
RedactionLogService redactionLogService;
|
||||
FileManagementStorageService fileManagementStorageService;
|
||||
|
||||
|
||||
@Transactional
|
||||
public void deleteComment(String dossierId, String fileId, List<Long> commentIds) {
|
||||
|
||||
for (var commentId : commentIds) {
|
||||
commentPersistenceService.softDelete(commentId, OffsetDateTime.now());
|
||||
}
|
||||
// update indicator
|
||||
fileStatusPersistenceService.updateHasComments(fileId, commentPersistenceService.fileHasComments(fileId));
|
||||
|
||||
// This is an ugly workaround, don't even look at it!
|
||||
// Basically we should change how comments work and not merge them into the redaction log.
|
||||
// if file is currently not analyzing, we can quickly change the redaction log, else we must wait for the analysis to finish.
|
||||
if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) {
|
||||
reprocess(dossierId, fileId);
|
||||
return;
|
||||
}
|
||||
fileStatusService.setStatusProcessing(fileId);
|
||||
RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId);
|
||||
redactionLog.getRedactionLogEntry().forEach(entry -> entry.getComments().removeIf(comment -> commentIds.contains(comment.getId())));
|
||||
fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog);
|
||||
fileStatusService.setStatusProcessed(fileId);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public Comments getComments(String fileId) {
|
||||
|
||||
return new Comments(commentPersistenceService.findCommentsByFileID(fileId, false)
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, entry -> MagicConverter.convert(entry.getValue(), Comment.class))));
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public CommentEntity addComment(String dossierId, String fileId, String annotationId, CommentRequest commentRequest) {
|
||||
|
||||
CommentEntity createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser());
|
||||
|
||||
fileStatusPersistenceService.updateHasComments(fileId, true);
|
||||
|
||||
// This is an ugly workaround, don't even look at it!
|
||||
// Basically we should change how comments work and not merge them into the redaction log.
|
||||
if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) {
|
||||
reprocess(dossierId, fileId);
|
||||
return createdComment;
|
||||
}
|
||||
fileStatusService.setStatusProcessing(fileId);
|
||||
RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId);
|
||||
redactionLog.getRedactionLogEntry()
|
||||
.stream()
|
||||
.filter(entry -> entry.getId().equals(annotationId))
|
||||
.forEach(entry -> entry.getComments().add(MagicConverter.convert(createdComment, RedactionLogComment.class)));
|
||||
fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog);
|
||||
fileStatusService.setStatusProcessed(fileId);
|
||||
return createdComment;
|
||||
}
|
||||
|
||||
|
||||
public Long addCommentAndGetId(String fileId, String annotationId, String comment, String user) {
|
||||
|
||||
if (comment == null) {
|
||||
return null;
|
||||
}
|
||||
return addComment(fileId, annotationId, comment, user).getId();
|
||||
}
|
||||
|
||||
|
||||
private CommentEntity addComment(String fileId, String annotationId, String comment, String user) {
|
||||
|
||||
if (comment == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return commentPersistenceService.insert(CommentEntity.builder()
|
||||
.text(comment)
|
||||
.fileId(fileId)
|
||||
.annotationId(annotationId)
|
||||
.user(user)
|
||||
.date(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
private void reprocess(String dossierId, String fileId) {
|
||||
|
||||
fileStatusService.setStatusReprocessForManual(dossierId, fileId, true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -9,12 +9,14 @@ import java.nio.file.StandardOpenOption;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.InternalServerErrorException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.StorageIdUtils;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.imported.ImportedRedactions;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid;
|
||||
import com.iqser.red.storage.commons.exception.StorageException;
|
||||
import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist;
|
||||
import com.iqser.red.storage.commons.service.StorageService;
|
||||
import com.knecon.fforesight.tenantcommons.TenantContext;
|
||||
@ -50,6 +52,7 @@ public class FileManagementStorageService {
|
||||
return storedObjectBytes;
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public InputStream getObject(String tenantId, String storageId) {
|
||||
|
||||
@ -83,11 +86,20 @@ public class FileManagementStorageService {
|
||||
return storageService.readJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.REDACTION_LOG), RedactionLog.class);
|
||||
} catch (StorageObjectDoesNotExist e) {
|
||||
log.debug("RedactionLog does not exist");
|
||||
throw new NotFoundException("RedactionLog does not exist");
|
||||
throw new NotFoundException(String.format("RedactionLog does not exist for Dossier ID \"%s\" and File ID \"%s\"!", dossierId, fileId));
|
||||
} catch (StorageException e) {
|
||||
throw new InternalServerErrorException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void storeRedactionLog(String dossierId, String fileId, RedactionLog redactionLog) {
|
||||
|
||||
storageService.storeJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.REDACTION_LOG), redactionLog);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public SectionGrid getSectionGrid(String dossierId, String fileId) {
|
||||
|
||||
try {
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.settings.FileManagementServiceSettings;
|
||||
@ -16,6 +15,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus;
|
||||
import com.iqser.red.service.search.v1.model.IndexMessageType;
|
||||
|
||||
import jakarta.transaction.Transactional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@ -53,7 +53,7 @@ public class FileStatusProcessingUpdateService {
|
||||
indexingService.addToIndexingQueue(IndexMessageType.INSERT, dossier.getDossierTemplateId(), dossierId, fileId, 2);
|
||||
}
|
||||
|
||||
manualRedactionService.updateProcessedDate(fileId, analyzeResult.getManualRedactions());
|
||||
manualRedactionService.updateProcessedDate(analyzeResult.getManualRedactions());
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
if (analyzeResult.getAddedFileAttributes() != null && !analyzeResult.getAddedFileAttributes().isEmpty()) {
|
||||
|
||||
@ -3,7 +3,6 @@ package com.iqser.red.service.persistence.management.v1.processor.service;
|
||||
import static com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingQueueNames.LAYOUT_PARSING_REQUEST_QUEUE;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -13,7 +12,6 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.iqser.red.service.pdftron.redaction.v1.api.model.ProcessUntouchedDocumentRequest;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration;
|
||||
@ -25,6 +23,7 @@ import com.iqser.red.service.persistence.management.v1.processor.model.NerServic
|
||||
import com.iqser.red.service.persistence.management.v1.processor.model.OCRStatusUpdateResponse;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.model.image.ImageServiceRequest;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.layoutparsing.LayoutParsingRequestFactory;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileAttributeConfigPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
|
||||
@ -1,761 +0,0 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service;
|
||||
|
||||
import com.google.common.hash.HashFunction;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.*;
|
||||
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.ConflictException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.*;
|
||||
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.IdRemoval;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus;
|
||||
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.redactionlog.RedactionLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
import feign.FeignException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ManualRedactionService {
|
||||
|
||||
private final DossierPersistenceService dossierPersistenceService;
|
||||
private final AddRedactionPersistenceService addRedactionPersistenceService;
|
||||
private final RemoveRedactionPersistenceService removeRedactionPersistenceService;
|
||||
private final ForceRedactionPersistenceService forceRedactionPersistenceService;
|
||||
private final CommentPersistenceService commentPersistenceService;
|
||||
private final FileStatusPersistenceService fileStatusPersistenceService;
|
||||
private final DictionaryPersistenceService dictionaryPersistenceService;
|
||||
private final FileManagementStorageService fileManagementStorageService;
|
||||
private final ImageRecategorizationPersistenceService recategorizationPersistenceService;
|
||||
private final LegalBasisChangePersistenceService legalBasisChangePersistenceService;
|
||||
private final ResizeRedactionPersistenceService resizeRedactionPersistenceService;
|
||||
private final FileStatusService fileStatusService;
|
||||
private final ManualRedactionProviderService manualRedactionProviderService;
|
||||
private final AnalysisFlagsCalculationService analysisFlagsCalculationService;
|
||||
private final StopwordService stopwordService;
|
||||
private final RedactionLogService redactionLogService;
|
||||
private final DictionaryManagementService dictionaryManagementService;
|
||||
private final HashFunction hashFunction = Hashing.murmur3_128();
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ManualAddResponse> addAddRedaction(String dossierId, String fileId, List<AddRedactionRequest> addRedactionRequests) {
|
||||
|
||||
var response = new ArrayList<ManualAddResponse>();
|
||||
|
||||
dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
|
||||
// validate add to dossier template dictionaries
|
||||
addRedactionRequests.forEach(request -> dictionaryManagementService.validateAddRemoveToDossierTemplateDictionary(request.getDossierTemplateTypeId(),
|
||||
request.isAddToDictionary(),
|
||||
request.isAddToAllDossiers()));
|
||||
|
||||
boolean actionPerformed = false;
|
||||
for (var addRedactionRequest : addRedactionRequests) {
|
||||
if (addRedactionRequest.isAddToDictionary()) {
|
||||
validateDictionary(addRedactionRequest);
|
||||
}
|
||||
|
||||
validatePositions(fileId, addRedactionRequest);
|
||||
String annotationId = hashFunction.hashString(fileId + addRedactionRequest, StandardCharsets.UTF_8).toString();
|
||||
addRedactionPersistenceService.insert(fileId, annotationId, addRedactionRequest);
|
||||
|
||||
Long commentId = null;
|
||||
if (addRedactionRequest.getComment() != null) {
|
||||
commentId = addComment(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser()).getId();
|
||||
}
|
||||
|
||||
handleAddToDictionary(fileId,
|
||||
annotationId,
|
||||
addRedactionRequest.getDossierTemplateTypeId(),
|
||||
addRedactionRequest.getValue(),
|
||||
addRedactionRequest.getStatus(),
|
||||
addRedactionRequest.isAddToDictionary(),
|
||||
addRedactionRequest.isAddToAllDossiers(),
|
||||
false,
|
||||
dossierId,
|
||||
addRedactionRequest.getDictionaryEntryType());
|
||||
|
||||
response.add(ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).build());
|
||||
actionPerformed = actionPerformed || addRedactionRequest.getStatus().equals(AnnotationStatus.APPROVED);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
if (actionPerformed) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
private void validateDictionary(AddRedactionRequest addRedactionRequest) {
|
||||
|
||||
try {
|
||||
if (!addRedactionRequest.isForceAddToDictionary() && stopwordService.isStopword(addRedactionRequest.getValue())) {
|
||||
throw new ConflictException("The entry you are trying to add is a stopword");
|
||||
}
|
||||
dictionaryPersistenceService.getType(addRedactionRequest.getDossierTemplateTypeId());
|
||||
} catch (NotFoundException e) {
|
||||
throw new BadRequestException("Invalid type: " + addRedactionRequest.getDossierTemplateTypeId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void validatePositions(String fileId, AddRedactionRequest addRedactionRequest) {
|
||||
|
||||
var numberOfPages = fileStatusService.getStatus(fileId).getNumberOfPages();
|
||||
addRedactionRequest.getPositions().stream().filter(p -> p.getPage() > numberOfPages).findAny().ifPresent(p -> new BadRequestException("Invalid page found in the request"));
|
||||
}
|
||||
|
||||
|
||||
private CommentEntity addComment(String fileId, String annotationId, String comment, String user) {
|
||||
|
||||
return commentPersistenceService.insert(CommentEntity.builder()
|
||||
.text(comment)
|
||||
.fileId(fileId)
|
||||
.annotationId(annotationId)
|
||||
.user(user)
|
||||
.date(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS))
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
private boolean handleAddToDictionary(String fileId,
|
||||
String annotationId,
|
||||
String dossierTemplateTypeId,
|
||||
String value,
|
||||
AnnotationStatus status,
|
||||
boolean addToDictionary,
|
||||
boolean addToAllDossiers,
|
||||
boolean revert,
|
||||
String dossierId,
|
||||
DictionaryEntryType dictionaryEntryType) {
|
||||
|
||||
if (status == AnnotationStatus.APPROVED) {
|
||||
|
||||
if (addToDictionary) {
|
||||
Set<String> typeIdsOfModifiedDictionaries = new HashSet<>();
|
||||
if (revert) {
|
||||
var addRedactionToRevert = addRedactionPersistenceService.findAddRedaction(fileId, annotationId);
|
||||
addRedactionToRevert.getTypeIdsOfModifiedDictionaries().forEach(typeId -> {
|
||||
removeFromDictionary(typeId, value, dossierId, fileId, dictionaryEntryType);
|
||||
});
|
||||
} else {
|
||||
if (addToAllDossiers) {
|
||||
var dictionaryEntriesToUnDelete = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplateTypeId, value, dictionaryEntryType);
|
||||
dictionaryEntriesToUnDelete.forEach(entry -> {
|
||||
typeIdsOfModifiedDictionaries.add(entry.getTypeId());
|
||||
addToDictionary(entry.getTypeId(), value, dossierId, fileId, dictionaryEntryType);
|
||||
});
|
||||
addToDictionary(dossierTemplateTypeId, value, dossierId, fileId, dictionaryEntryType);
|
||||
typeIdsOfModifiedDictionaries.add(dossierTemplateTypeId);
|
||||
} else {
|
||||
addToDictionary(dossierTemplateTypeId + ":" + dossierId, value, dossierId, fileId, dictionaryEntryType);
|
||||
typeIdsOfModifiedDictionaries.add(dossierTemplateTypeId + ":" + dossierId);
|
||||
}
|
||||
addRedactionPersistenceService.updateStatus(fileId, annotationId, status, true, typeIdsOfModifiedDictionaries);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
addRedactionPersistenceService.updateStatus(fileId, annotationId, status, false, null);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private void reprocess(String dossierId, String fileId) {
|
||||
|
||||
fileStatusService.setStatusReprocessForManual(dossierId, fileId, true);
|
||||
}
|
||||
|
||||
|
||||
public ManualRedactionEntryEntity getAddRedaction(String fileId, String annotationId) {
|
||||
|
||||
return addRedactionPersistenceService.findAddRedaction(fileId, annotationId);
|
||||
}
|
||||
|
||||
|
||||
private void removeFromDictionary(String typeId, String value, String dossierId, String fileId, DictionaryEntryType dictionaryEntryType) {
|
||||
|
||||
try {
|
||||
log.debug("Deleting entries to {} for {} / {}", typeId, dossierId, fileId);
|
||||
dictionaryManagementService.deleteEntries(typeId, List.of(value), dictionaryEntryType != null ? dictionaryEntryType : DictionaryEntryType.ENTRY);
|
||||
} catch (FeignException e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void addToDictionary(String typeId, String value, String dossierId, String fileId, DictionaryEntryType dictionaryEntryType) {
|
||||
|
||||
try {
|
||||
log.debug("Adding entry: {} to {} for {} / {}", value, typeId, dossierId, fileId);
|
||||
dictionaryManagementService.addEntries(typeId, List.of(value), false, false, dictionaryEntryType != null ? dictionaryEntryType : DictionaryEntryType.ENTRY);
|
||||
} catch (Exception e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<ManualAddResponse> addRemoveRedaction(String dossierId, String fileId, List<RemoveRedactionRequest> removeRedactionRequests) {
|
||||
|
||||
var response = new ArrayList<ManualAddResponse>();
|
||||
var dossier = dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
RedactionLog redactionLog = fileManagementStorageService.getRedactionLog(dossier.getId(), fileId);
|
||||
|
||||
var requiresReAnalysis = false;
|
||||
var manualRedactions = manualRedactionProviderService.getManualRedactions(fileId);
|
||||
|
||||
//validate removing from dossier template dictionary
|
||||
removeRedactionRequests.forEach(request -> {
|
||||
if (request.isRemoveFromDictionary()) {
|
||||
RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, request.getAnnotationId());
|
||||
var dossierTemplateTypeId = toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId());
|
||||
dictionaryManagementService.validateAddRemoveToDossierTemplateDictionary(dossierTemplateTypeId,
|
||||
request.isRemoveFromDictionary(),
|
||||
request.isRemoveFromAllDossiers());
|
||||
}
|
||||
});
|
||||
|
||||
for (var removeRedactionRequest : removeRedactionRequests) {
|
||||
|
||||
if (manualAddRedactionsContains(manualRedactions, removeRedactionRequest.getAnnotationId()) && AnnotationStatus.APPROVED.equals(removeRedactionRequest.getStatus())) {
|
||||
log.info("hard delete ManualRedactions for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId());
|
||||
manualRedactionProviderService.hardDeleteManualRedactions(fileId, removeRedactionRequest.getAnnotationId());
|
||||
} else {
|
||||
|
||||
log.info("add removeRedaction for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId());
|
||||
var idRemoval = MagicConverter.convert(removeRedactionPersistenceService.insert(fileId, removeRedactionRequest), IdRemoval.class);
|
||||
|
||||
Long commentId = null;
|
||||
if (removeRedactionRequest.getComment() != null) {
|
||||
commentId = addComment(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getComment(), removeRedactionRequest.getUser()).getId();
|
||||
}
|
||||
boolean matchingEntryFound = false;
|
||||
if (!removeRedactionRequest.isRemoveFromDictionary() && AnnotationStatus.APPROVED.equals(removeRedactionRequest.getStatus())) {
|
||||
try {
|
||||
getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId());
|
||||
matchingEntryFound = true;
|
||||
} catch (NotFoundException e) {
|
||||
log.warn("No matching entry found in redaction log for annotation id {}", removeRedactionRequest.getAnnotationId());
|
||||
}
|
||||
|
||||
requiresReAnalysis = requiresReAnalysis || matchingEntryFound;
|
||||
}
|
||||
|
||||
var removedFromDictionary = handleRemoveFromDictionary(redactionLog,
|
||||
dossier,
|
||||
fileId,
|
||||
removeRedactionRequest.getAnnotationId(),
|
||||
removeRedactionRequest.getStatus(),
|
||||
removeRedactionRequest.isRemoveFromDictionary(),
|
||||
removeRedactionRequest.isRemoveFromAllDossiers(),
|
||||
false);
|
||||
|
||||
if (!matchingEntryFound && !removedFromDictionary && idRemoval.isApproved()) {
|
||||
removeRedactionPersistenceService.markAsProcessed(idRemoval);
|
||||
}
|
||||
|
||||
requiresReAnalysis = requiresReAnalysis || removedFromDictionary;
|
||||
|
||||
response.add(ManualAddResponse.builder().annotationId(removeRedactionRequest.getAnnotationId()).commentId(commentId).build());
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresReAnalysis) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
private boolean manualAddRedactionsContains(ManualRedactions manualRedactions, String annotationId) {
|
||||
|
||||
return manualRedactions.getEntriesToAdd().stream().anyMatch(m -> annotationId.equals(m.getAnnotationId()));
|
||||
}
|
||||
|
||||
|
||||
private boolean handleRemoveFromDictionary(RedactionLog redactionLog,
|
||||
DossierEntity dossier,
|
||||
String fileId,
|
||||
String annotationId,
|
||||
AnnotationStatus status,
|
||||
boolean removeFromDictionary,
|
||||
boolean removeFromAllDossiers,
|
||||
boolean revert) {
|
||||
|
||||
if (status == AnnotationStatus.APPROVED) {
|
||||
|
||||
Set<String> typeIdsOfModifiedDictionaries = new HashSet<>();
|
||||
|
||||
if (removeFromDictionary) {
|
||||
|
||||
RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, annotationId);
|
||||
|
||||
if (revert) {
|
||||
var idRemovalEntity = removeRedactionPersistenceService.findRemoveRedaction(fileId, annotationId);
|
||||
idRemovalEntity.getTypeIdsOfModifiedDictionaries().forEach(changedTypeId -> {
|
||||
addToDictionary(changedTypeId, redactionLogEntry.getValue(), dossier.getId(), fileId, DictionaryEntryType.ENTRY);
|
||||
});
|
||||
} else {
|
||||
if (removeFromAllDossiers) {
|
||||
var dictionaryEntriesToRemove = dictionaryManagementService.getAllEntriesInDossierTemplate(toTypeId(redactionLogEntry.getType(),
|
||||
dossier.getDossierTemplateId()), redactionLogEntry.getValue(), DictionaryEntryType.ENTRY);
|
||||
dictionaryEntriesToRemove.forEach(entry -> {
|
||||
typeIdsOfModifiedDictionaries.add(entry.getTypeId());
|
||||
removeFromDictionary(entry.getTypeId(), entry.getValue(), dossier.getId(), fileId, DictionaryEntryType.ENTRY);
|
||||
});
|
||||
} else {
|
||||
typeIdsOfModifiedDictionaries.add(toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId()));
|
||||
removeFromDictionary(toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId()),
|
||||
redactionLogEntry.getValue(),
|
||||
dossier.getId(),
|
||||
fileId,
|
||||
DictionaryEntryType.ENTRY);
|
||||
}
|
||||
|
||||
// This is needed to remove resizeRedactions with addToDictionary.
|
||||
removeResizeRedactionsWithAddToDictionary(dossier.getDossierTemplateId(), redactionLogEntry.getValue());
|
||||
}
|
||||
|
||||
removeRedactionPersistenceService.updateStatus(fileId, annotationId, status, true, typeIdsOfModifiedDictionaries);
|
||||
return true;
|
||||
}
|
||||
removeRedactionPersistenceService.updateStatus(fileId, annotationId, status, false, typeIdsOfModifiedDictionaries);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private RedactionLogEntry getRedactionLogEntry(RedactionLog redactionLog, String annotationId) {
|
||||
|
||||
Optional<RedactionLogEntry> redactionLogEntryOptional = redactionLog.getRedactionLogEntry().stream().filter(entry -> entry.getId().equals(annotationId)).findFirst();
|
||||
|
||||
if (redactionLogEntryOptional.isEmpty()) {
|
||||
throw new NotFoundException("Annotation does not exist in redaction log.");
|
||||
}
|
||||
|
||||
var redactionLogEntry = redactionLogEntryOptional.get();
|
||||
return redactionLogEntry;
|
||||
}
|
||||
|
||||
|
||||
private void removeResizeRedactionsWithAddToDictionary(String dossierTemplateId, String redactionLogEntryValue) {
|
||||
|
||||
var resizeRedactionsWithSameValue = resizeRedactionPersistenceService.findByAnnotationStatusAndValue(AnnotationStatus.APPROVED, redactionLogEntryValue);
|
||||
resizeRedactionsWithSameValue.forEach(resizeRedaction -> {
|
||||
var file = fileStatusPersistenceService.getStatus(resizeRedaction.getId().getFileId());
|
||||
var dossierForResizeRedaction = dossierPersistenceService.findByDossierId(file.getDossierId());
|
||||
if (!file.getWorkflowStatus().equals(WorkflowStatus.APPROVED) && dossierTemplateId.equals(dossierForResizeRedaction.getDossierTemplateId())) {
|
||||
resizeRedactionPersistenceService.hardDelete(resizeRedaction.getId().getFileId(), resizeRedaction.getId().getAnnotationId());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ManualAddResponse> addForceRedaction(String dossierId, String fileId, List<ForceRedactionRequest> forceRedactionRequests) {
|
||||
|
||||
var response = new ArrayList<ManualAddResponse>();
|
||||
dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
var actionPerformed = false;
|
||||
|
||||
for (var forceRedactionRequest : forceRedactionRequests) {
|
||||
forceRedactionPersistenceService.insert(fileId, forceRedactionRequest);
|
||||
|
||||
Long commentId = null;
|
||||
if (forceRedactionRequest.getComment() != null) {
|
||||
|
||||
commentId = addComment(fileId, forceRedactionRequest.getAnnotationId(), forceRedactionRequest.getComment(), forceRedactionRequest.getUser()).getId();
|
||||
}
|
||||
actionPerformed = actionPerformed || forceRedactionRequest.getStatus().equals(AnnotationStatus.APPROVED);
|
||||
response.add(ManualAddResponse.builder().annotationId(forceRedactionRequest.getAnnotationId()).commentId(commentId).build());
|
||||
}
|
||||
|
||||
if (actionPerformed) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ManualAddResponse> addLegalBasisChange(String dossierId, String fileId, List<LegalBasisChangeRequest> legalBasisChangeRequests) {
|
||||
|
||||
var response = new ArrayList<ManualAddResponse>();
|
||||
dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
|
||||
for (var legalBasisChangeRequest : legalBasisChangeRequests) {
|
||||
legalBasisChangePersistenceService.insert(fileId, legalBasisChangeRequest);
|
||||
|
||||
Long commentId = null;
|
||||
if (legalBasisChangeRequest.getComment() != null) {
|
||||
|
||||
commentId = addComment(fileId, legalBasisChangeRequest.getAnnotationId(), legalBasisChangeRequest.getComment(), legalBasisChangeRequest.getUser()).getId();
|
||||
}
|
||||
|
||||
response.add(ManualAddResponse.builder().annotationId(legalBasisChangeRequest.getAnnotationId()).commentId(commentId).build());
|
||||
}
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ManualAddResponse> addImageRecategorization(String dossierId, String fileId, List<ImageRecategorizationRequest> imageRecategorizationRequests) {
|
||||
|
||||
var response = new ArrayList<ManualAddResponse>();
|
||||
var actionPerformed = false;
|
||||
dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
|
||||
for (var imageRecategorizationRequest : imageRecategorizationRequests) {
|
||||
recategorizationPersistenceService.insert(fileId, imageRecategorizationRequest);
|
||||
|
||||
Long commentId = null;
|
||||
if (imageRecategorizationRequest.getComment() != null) {
|
||||
|
||||
commentId = addComment(fileId,
|
||||
imageRecategorizationRequest.getAnnotationId(),
|
||||
imageRecategorizationRequest.getComment(),
|
||||
imageRecategorizationRequest.getUser()).getId();
|
||||
}
|
||||
|
||||
actionPerformed = actionPerformed || imageRecategorizationRequest.getStatus().equals(AnnotationStatus.APPROVED);
|
||||
|
||||
response.add(ManualAddResponse.builder().annotationId(imageRecategorizationRequest.getAnnotationId()).commentId(commentId).build());
|
||||
}
|
||||
if (actionPerformed) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
public CommentEntity addComment(String fileId, String annotationId, CommentRequest commentRequest) {
|
||||
|
||||
var createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser());
|
||||
|
||||
fileStatusPersistenceService.updateHasComments(fileId, true);
|
||||
|
||||
return createdComment;
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void deleteAddRedaction(String dossierId, String fileId, List<String> annotationIds) {
|
||||
|
||||
var dossier = dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
var actionPerformed = false;
|
||||
|
||||
for (var annotationId : annotationIds) {
|
||||
var addRedaction = getAddRedaction(fileId, annotationId);
|
||||
actionPerformed = actionPerformed || handleAddToDictionary(fileId,
|
||||
annotationId,
|
||||
addRedaction.getTypeId(),
|
||||
addRedaction.getValue(),
|
||||
addRedaction.getStatus(),
|
||||
addRedaction.isAddToDictionary(),
|
||||
addRedaction.isAddToAllDossiers(),
|
||||
true,
|
||||
dossier.getId(),
|
||||
addRedaction.getDictionaryEntryType());
|
||||
addRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
}
|
||||
|
||||
if (actionPerformed) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void deleteRemoveRedaction(String dossierId, String fileId, List<String> annotationIds) {
|
||||
|
||||
var dossier = dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
var actionPerformed = false;
|
||||
RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId, true, true);
|
||||
|
||||
for (var annotationId : annotationIds) {
|
||||
|
||||
var removeRedaction = getRemoveRedaction(fileId, annotationId);
|
||||
|
||||
var removedFromDictionary = handleRemoveFromDictionary(redactionLog,
|
||||
dossier,
|
||||
fileId,
|
||||
annotationId,
|
||||
removeRedaction.getStatus(),
|
||||
removeRedaction.isRemoveFromDictionary(),
|
||||
removeRedaction.isRemoveFromAllDossiers(),
|
||||
true);
|
||||
|
||||
actionPerformed = actionPerformed || removedFromDictionary;
|
||||
removeRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
}
|
||||
|
||||
if (actionPerformed) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
private IdRemovalEntity getRemoveRedaction(String fileId, String annotationId) {
|
||||
|
||||
return removeRedactionPersistenceService.findRemoveRedaction(fileId, annotationId);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void deleteForceRedaction(String dossierId, String fileId, List<String> annotationIds) {
|
||||
|
||||
var now = OffsetDateTime.now();
|
||||
|
||||
for (var annotationId : annotationIds) {
|
||||
forceRedactionPersistenceService.softDelete(fileId, annotationId, now);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void deleteLegalBasisChange(String dossierId, String fileId, List<String> annotationIds) {
|
||||
|
||||
for (var annotationId : annotationIds) {
|
||||
legalBasisChangePersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void deleteImageRecategorization(String dossierId, String fileId, List<String> annotationIds) {
|
||||
|
||||
var actionPerformed = false;
|
||||
for (var annotationId : annotationIds) {
|
||||
var imageRecategorization = getImageRecategorization(fileId, annotationId);
|
||||
|
||||
recategorizationPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
|
||||
actionPerformed = actionPerformed || !AnnotationStatus.REQUESTED.equals(imageRecategorization.getStatus());
|
||||
}
|
||||
|
||||
if (actionPerformed) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
private ManualImageRecategorizationEntity getImageRecategorization(String fileId, String annotationId) {
|
||||
|
||||
return recategorizationPersistenceService.findRecategorization(fileId, annotationId);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void deleteComment(String fileId, List<Long> commentIds) {
|
||||
|
||||
for (var commentId : commentIds) {
|
||||
commentPersistenceService.softDelete(commentId, OffsetDateTime.now());
|
||||
}
|
||||
// update indicator
|
||||
fileStatusPersistenceService.updateHasComments(fileId, commentPersistenceService.fileHasComments(fileId));
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void deleteResizeRedaction(String dossierId, String fileId, List<String> annotationIds) {
|
||||
|
||||
OffsetDateTime now = OffsetDateTime.now();
|
||||
for (var annotationId : annotationIds) {
|
||||
resizeRedactionPersistenceService.softDelete(fileId, annotationId, now);
|
||||
}
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ManualAddResponse> addResizeRedaction(String dossierId, String fileId, List<ResizeRedactionRequest> resizeRedactionRequests) {
|
||||
|
||||
var response = new ArrayList<ManualAddResponse>();
|
||||
|
||||
RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId, true, true);
|
||||
|
||||
for (ResizeRedactionRequest resizeRedactionRequest : resizeRedactionRequests) {
|
||||
|
||||
var resizeRedaction = resizeRedactionPersistenceService.insert(fileId, resizeRedactionRequest);
|
||||
|
||||
if (resizeRedactionRequest.getComment() != null) {
|
||||
var commentId = addComment(fileId, resizeRedactionRequest.getAnnotationId(), resizeRedactionRequest.getComment(), resizeRedactionRequest.getUser()).getId();
|
||||
response.add(ManualAddResponse.builder().annotationId(resizeRedactionRequest.getAnnotationId()).commentId(commentId).build());
|
||||
}
|
||||
|
||||
updateDictionaryForResizeRedactions(dossierId, fileId, resizeRedaction, redactionLog);
|
||||
}
|
||||
|
||||
if (resizeRedactionRequests.stream().anyMatch(resize -> AnnotationStatus.APPROVED.equals(resize.getStatus()))) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
private void updateDictionaryForResizeRedactions(String dossierId, String fileId, ManualResizeRedactionEntity resizeRedaction, RedactionLog redactionLog) {
|
||||
|
||||
RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, resizeRedaction.getId().getAnnotationId());
|
||||
|
||||
if (resizeRedaction.getUpdateDictionary() != null && resizeRedaction.getUpdateDictionary() && resizeRedaction.getStatus()
|
||||
.equals(AnnotationStatus.APPROVED) && (redactionLogEntry.isDictionaryEntry() || redactionLogEntry.isDossierDictionaryEntry())) {
|
||||
|
||||
var dossier = dossierPersistenceService.findByDossierId(dossierId);
|
||||
|
||||
var typeId = buildTypeId(redactionLogEntry, resizeRedaction, dossier);
|
||||
var newValue = resizeRedaction.getValue();
|
||||
var oldValue = redactionLogEntry.getValue();
|
||||
var dictionaryEntryType = getDictionaryEntryType(redactionLogEntry);
|
||||
|
||||
boolean isShrinking = oldValue != null && oldValue.length() > newValue.length();
|
||||
|
||||
Set<String> typeIdsOfModifiedDictionaries = new HashSet<>();
|
||||
|
||||
if (isShrinking) {
|
||||
log.info("Remove old value '{}' from dictionary", oldValue);
|
||||
removeFromDictionary(typeId, oldValue, dossierId, fileId, dictionaryEntryType);
|
||||
typeIdsOfModifiedDictionaries.add(typeId);
|
||||
|
||||
if (resizeRedaction.isAddToAllDossiers() && redactionLogEntry.isDictionaryEntry()) {
|
||||
String dossierTemplateId = dossier.getDossierTemplateId();
|
||||
var dossiersOfThisDossierTemplate = dossierPersistenceService.findAllDossiersForDossierTemplateId(dossierTemplateId);
|
||||
var type = redactionLogEntry.getType();
|
||||
dossiersOfThisDossierTemplate.forEach(dossierEntity -> {
|
||||
var typeIdOfDossierEntity = toTypeId(type, dossierTemplateId, dossierEntity.getId());
|
||||
removeFromDictionary(typeIdOfDossierEntity, oldValue, dossierId, fileId, dictionaryEntryType);
|
||||
typeIdsOfModifiedDictionaries.add(typeIdOfDossierEntity);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.info("Add new value '{}' to dictionary", newValue);
|
||||
addToDictionary(typeId, newValue, dossierId, fileId, dictionaryEntryType);
|
||||
typeIdsOfModifiedDictionaries.add(typeId);
|
||||
|
||||
resizeRedactionPersistenceService.updateStatus(resizeRedaction.getId().getFileId(),
|
||||
resizeRedaction.getId().getAnnotationId(),
|
||||
resizeRedaction.getStatus(),
|
||||
typeIdsOfModifiedDictionaries);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String buildTypeId(RedactionLogEntry redactionLogEntry, ManualResizeRedactionEntity resizeRedaction, DossierEntity dossier) {
|
||||
|
||||
if (resizeRedaction.isAddToAllDossiers()) {
|
||||
return toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId());
|
||||
} else {
|
||||
return toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private DictionaryEntryType getDictionaryEntryType(RedactionLogEntry redactionLogEntry) {
|
||||
|
||||
if (redactionLogEntry.isRecommendation() && redactionLogEntry.isFalsePositive()) {
|
||||
return DictionaryEntryType.FALSE_RECOMMENDATION;
|
||||
} else if (redactionLogEntry.isFalsePositive()) {
|
||||
return DictionaryEntryType.FALSE_POSITIVE;
|
||||
} else {
|
||||
return DictionaryEntryType.ENTRY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ManualRedactions getManualRedactions(String fileId) {
|
||||
|
||||
return manualRedactionProviderService.getManualRedactions(fileId);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void updateProcessedDate(String fileId, ManualRedactions manualRedactions) {
|
||||
|
||||
if (manualRedactions != null) {
|
||||
|
||||
if (manualRedactions.getEntriesToAdd() != null) {
|
||||
manualRedactions.getEntriesToAdd().forEach(e -> {
|
||||
if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) {
|
||||
addRedactionPersistenceService.markAsProcessed(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (manualRedactions.getIdsToRemove() != null) {
|
||||
manualRedactions.getIdsToRemove().forEach(e -> {
|
||||
if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) {
|
||||
removeRedactionPersistenceService.markAsProcessed(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (manualRedactions.getForceRedactions() != null) {
|
||||
manualRedactions.getForceRedactions().forEach(e -> {
|
||||
if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) {
|
||||
forceRedactionPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId());
|
||||
}
|
||||
});
|
||||
}
|
||||
if (manualRedactions.getImageRecategorization() != null) {
|
||||
manualRedactions.getImageRecategorization().forEach(e -> {
|
||||
if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) {
|
||||
recategorizationPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId());
|
||||
}
|
||||
});
|
||||
}
|
||||
if (manualRedactions.getResizeRedactions() != null) {
|
||||
manualRedactions.getResizeRedactions().forEach(e -> {
|
||||
if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) {
|
||||
resizeRedactionPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,26 +2,17 @@ package com.iqser.red.service.persistence.management.v1.processor.service;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.redactionlog.RedactionLogMergeService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.redactionlog.RedactionRequest;
|
||||
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.Type;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.FilteredRedactionLogRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid;
|
||||
|
||||
import feign.FeignException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Service
|
||||
@ -29,59 +20,29 @@ import lombok.RequiredArgsConstructor;
|
||||
public class RedactionLogService {
|
||||
|
||||
private final FileManagementStorageService fileManagementStorageService;
|
||||
private final ManualRedactionProviderService manualRedactionService;
|
||||
private final DossierPersistenceService dossierPersistenceService;
|
||||
private final FileStatusService fileStatusService;
|
||||
private final ColorsService colorsService;
|
||||
private final DictionaryPersistenceService dictionaryPersistenceService;
|
||||
private final RedactionLogMergeService redactionLogMergeService;
|
||||
|
||||
|
||||
public RedactionLog getRedactionLog(String dossierId, String fileId, boolean withManualRedactions, boolean includeFalsePositives) {
|
||||
public RedactionLog getRedactionLog(String dossierId, String fileId) {
|
||||
|
||||
return getRedactionLog(dossierId, fileId, null, withManualRedactions, includeFalsePositives);
|
||||
return getRedactionLog(dossierId, fileId, Collections.emptyList());
|
||||
}
|
||||
|
||||
|
||||
public RedactionLog getRedactionLog(String dossierId, String fileId, List<String> excludedTypes, boolean withManualRedactions, boolean includeFalsePositives) {
|
||||
public RedactionLog getRedactionLog(String dossierId, String fileId, List<String> excludedTypes) {
|
||||
|
||||
var fileStatus = fileStatusService.getStatus(fileId);
|
||||
|
||||
RedactionLog redactionLog;
|
||||
|
||||
if (withManualRedactions) {
|
||||
var dossier = dossierPersistenceService.findByDossierId(dossierId);
|
||||
var manualRedactions = manualRedactionService.getManualRedactions(fileId);
|
||||
var colors = MagicConverter.convert(colorsService.getColors(dossier.getDossierTemplateId()), Colors.class);
|
||||
var types = MagicConverter.convert(dictionaryPersistenceService.getAllTypesForDossierTemplate(dossier.getDossierTemplateId(), true), Type.class);
|
||||
var dossierTypes = MagicConverter.convert(dictionaryPersistenceService.getAllTypesForDossier(dossierId, true), Type.class);
|
||||
types.addAll(dossierTypes);
|
||||
|
||||
try {
|
||||
redactionLog = redactionLogMergeService.provideRedactionLog(RedactionRequest.builder()
|
||||
.dossierId(dossierId)
|
||||
.fileId(fileId)
|
||||
.manualRedactions(manualRedactions)
|
||||
.dossierTemplateId(dossier.getDossierTemplateId())
|
||||
.excludedPages(fileStatus.getExcludedPages())
|
||||
.includeFalsePositives(includeFalsePositives)
|
||||
.colors(colors)
|
||||
.types(types)
|
||||
.build());
|
||||
} catch (FeignException e) {
|
||||
if (e.status() == HttpStatus.NOT_FOUND.value()) {
|
||||
throw new NotFoundException(e.getMessage());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
redactionLog = fileManagementStorageService.getRedactionLog(dossierId, fileId);
|
||||
}
|
||||
redactionLog = fileManagementStorageService.getRedactionLog(dossierId, fileId);
|
||||
|
||||
if (fileStatus.isExcluded()) {
|
||||
redactionLog.setRedactionLogEntry(new ArrayList<>());
|
||||
}
|
||||
|
||||
if (fileStatus.isHasUpdates())
|
||||
|
||||
if (excludedTypes != null) {
|
||||
redactionLog.getRedactionLogEntry().removeIf(nextEntry -> excludedTypes.contains(nextEntry.getType()));
|
||||
}
|
||||
@ -102,11 +63,7 @@ public class RedactionLogService {
|
||||
filteredRedactionLogRequest.setSpecifiedDate(OffsetDateTime.MIN);
|
||||
}
|
||||
|
||||
var redactionLog = getRedactionLog(dossierId,
|
||||
fileId,
|
||||
filteredRedactionLogRequest.getExcludedTypes(),
|
||||
filteredRedactionLogRequest.isWithManualRedactions(),
|
||||
filteredRedactionLogRequest.isIncludeFalsePositives());
|
||||
var redactionLog = getRedactionLog(dossierId, fileId, filteredRedactionLogRequest.getExcludedTypes());
|
||||
var redactionLogEntries = redactionLog.getRedactionLogEntry();
|
||||
|
||||
Iterator<RedactionLogEntry> it = redactionLogEntries.iterator();
|
||||
|
||||
@ -0,0 +1,304 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.dictionarymerge.commons.DictionaryEntry;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualResizeRedactionEntity;
|
||||
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.ConflictException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.StopwordService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithAddToDictionary;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithRemoveFromDictionary;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus;
|
||||
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.redactionlog.RedactionLogEntry;
|
||||
|
||||
import feign.FeignException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class ManualRedactionDictionaryUpdateHandler {
|
||||
|
||||
DictionaryManagementService dictionaryManagementService;
|
||||
DictionaryPersistenceService dictionaryPersistenceService;
|
||||
FileStatusPersistenceService fileStatusPersistenceService;
|
||||
ResizeRedactionPersistenceService resizeRedactionPersistenceService;
|
||||
DossierPersistenceService dossierPersistenceService;
|
||||
StopwordService stopwordService;
|
||||
|
||||
|
||||
public Set<String> handleAddToDictionaryAndReturnModifiedTypeIds(String fileId, String value, ManualRequestWithAddToDictionary manualRequestWithAddToDictionary) {
|
||||
|
||||
if (!manualRequestWithAddToDictionary.isAddToDictionary()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Set<String> typeIdsOfModifiedDictionaries = new HashSet<>();
|
||||
if (manualRequestWithAddToDictionary.isAddToAllDossiers()) {
|
||||
return addToDossierTemplateDictionary(fileId, value, manualRequestWithAddToDictionary, typeIdsOfModifiedDictionaries);
|
||||
}
|
||||
return addToDossierDictionary(fileId, value, manualRequestWithAddToDictionary, typeIdsOfModifiedDictionaries);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private Set<String> addToDossierTemplateDictionary(String fileId, String value, ManualRequestWithAddToDictionary manualRequestWithAddToDictionary, Set<String> typeIdsOfModifiedDictionaries) {
|
||||
|
||||
List<DictionaryEntry> dictionaryEntriesToUnDelete = dictionaryManagementService.getAllEntriesInDossierTemplate(manualRequestWithAddToDictionary.getDossierTemplateTypeId(),
|
||||
value, manualRequestWithAddToDictionary.getDictionaryEntryType());
|
||||
dictionaryEntriesToUnDelete.forEach(entry -> {
|
||||
typeIdsOfModifiedDictionaries.add(entry.getTypeId());
|
||||
addToDictionary(entry.getTypeId(), value,
|
||||
manualRequestWithAddToDictionary.getDossierId(), fileId,
|
||||
manualRequestWithAddToDictionary.getDictionaryEntryType());
|
||||
});
|
||||
addToDictionary(manualRequestWithAddToDictionary.getDossierTemplateTypeId(), value,
|
||||
manualRequestWithAddToDictionary.getDossierId(), fileId,
|
||||
manualRequestWithAddToDictionary.getDictionaryEntryType());
|
||||
typeIdsOfModifiedDictionaries.add(manualRequestWithAddToDictionary.getDossierTemplateTypeId());
|
||||
return typeIdsOfModifiedDictionaries;
|
||||
}
|
||||
|
||||
|
||||
private Set<String> addToDossierDictionary(String fileId,
|
||||
String value,
|
||||
ManualRequestWithAddToDictionary manualRequestWithAddToDictionary,
|
||||
Set<String> typeIdsOfModifiedDictionaries) {
|
||||
|
||||
addToDictionary(manualRequestWithAddToDictionary.getDossierTemplateTypeId() + ":" + manualRequestWithAddToDictionary.getDossierId(),
|
||||
value,
|
||||
manualRequestWithAddToDictionary.getDossierId(),
|
||||
fileId,
|
||||
manualRequestWithAddToDictionary.getDictionaryEntryType());
|
||||
typeIdsOfModifiedDictionaries.add(manualRequestWithAddToDictionary.getDossierTemplateTypeId() + ":" + manualRequestWithAddToDictionary.getDossierId());
|
||||
return typeIdsOfModifiedDictionaries;
|
||||
}
|
||||
|
||||
public Set<String> handleRemoveFromDictionaryAndReturnModifiedTypeIds(RedactionLogEntry redactionLogEntry,
|
||||
String fileId,
|
||||
String dossierId,
|
||||
String dossierTemplateId,
|
||||
ManualRequestWithRemoveFromDictionary manualRequestWithRemoveFromDictionary) {
|
||||
|
||||
if (!manualRequestWithRemoveFromDictionary.isRemoveFromDictionary()) {
|
||||
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<String> typeIdsOfModifiedDictionaries = new HashSet<>();
|
||||
if (manualRequestWithRemoveFromDictionary.isRemoveFromAllDossiers()) {
|
||||
var dictionaryEntriesToRemove = dictionaryManagementService.getAllEntriesInDossierTemplate(toTypeId(redactionLogEntry.getType(), dossierTemplateId),
|
||||
redactionLogEntry.getValue(), getDictionaryEntryType(redactionLogEntry));
|
||||
dictionaryEntriesToRemove.forEach(entry -> {
|
||||
typeIdsOfModifiedDictionaries.add(entry.getTypeId());
|
||||
removeFromDictionary(entry.getTypeId(), entry.getValue(), dossierId, fileId, getDictionaryEntryType(redactionLogEntry));
|
||||
});
|
||||
} else {
|
||||
typeIdsOfModifiedDictionaries.add(toTypeId(redactionLogEntry.getType(), dossierTemplateId, dossierId));
|
||||
removeFromDictionary(toTypeId(redactionLogEntry.getType(), dossierTemplateId, dossierId), redactionLogEntry.getValue(), dossierId, fileId, getDictionaryEntryType(redactionLogEntry));
|
||||
}
|
||||
|
||||
// This is needed to remove resizeRedactions with addToDictionary.
|
||||
removeResizeRedactionsWithAddToDictionary(dossierTemplateId, redactionLogEntry.getValue());
|
||||
|
||||
return typeIdsOfModifiedDictionaries;
|
||||
}
|
||||
|
||||
|
||||
public Set<String> updateDictionaryForResizeRedactions(String dossierId, String fileId, ManualResizeRedactionEntity resizeRedaction, RedactionLogEntry redactionLogEntry) {
|
||||
|
||||
if (resizeRedaction.getUpdateDictionary() != null && resizeRedaction.getUpdateDictionary() && resizeRedaction.getStatus()
|
||||
.equals(AnnotationStatus.APPROVED) && (redactionLogEntry.isDictionaryEntry() || redactionLogEntry.isDossierDictionaryEntry())) {
|
||||
|
||||
var dossier = dossierPersistenceService.findByDossierId(dossierId);
|
||||
|
||||
var typeId = buildTypeId(redactionLogEntry, resizeRedaction, dossier);
|
||||
var newValue = resizeRedaction.getValue();
|
||||
var oldValue = redactionLogEntry.getValue();
|
||||
var dictionaryEntryType = getDictionaryEntryType(redactionLogEntry);
|
||||
|
||||
boolean isShrinking = oldValue != null && oldValue.length() > newValue.length();
|
||||
|
||||
Set<String> typeIdsOfModifiedDictionaries = new HashSet<>();
|
||||
|
||||
if (isShrinking) {
|
||||
log.info("Remove old value '{}' from dictionary", oldValue);
|
||||
removeFromDictionary(typeId, oldValue, dossierId, fileId, dictionaryEntryType);
|
||||
typeIdsOfModifiedDictionaries.add(typeId);
|
||||
|
||||
if (resizeRedaction.isAddToAllDossiers() && redactionLogEntry.isDictionaryEntry()) {
|
||||
String dossierTemplateId = dossier.getDossierTemplateId();
|
||||
var dossiersOfThisDossierTemplate = dossierPersistenceService.findAllDossiersForDossierTemplateId(dossierTemplateId);
|
||||
var type = redactionLogEntry.getType();
|
||||
dossiersOfThisDossierTemplate.forEach(dossierEntity -> {
|
||||
var typeIdOfDossierEntity = toTypeId(type, dossierTemplateId, dossierEntity.getId());
|
||||
removeFromDictionary(typeIdOfDossierEntity, oldValue, dossierId, fileId, dictionaryEntryType);
|
||||
typeIdsOfModifiedDictionaries.add(typeIdOfDossierEntity);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.info("Add new value '{}' to dictionary", newValue);
|
||||
addToDictionary(typeId, newValue, dossierId, fileId, dictionaryEntryType);
|
||||
typeIdsOfModifiedDictionaries.add(typeId);
|
||||
|
||||
return typeIdsOfModifiedDictionaries;
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
|
||||
private String buildTypeId(RedactionLogEntry redactionLogEntry, ManualResizeRedactionEntity resizeRedaction, DossierEntity dossier) {
|
||||
|
||||
if (resizeRedaction.isAddToAllDossiers()) {
|
||||
return toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId());
|
||||
} else {
|
||||
return toTypeId(redactionLogEntry.getType(), dossier.getDossierTemplateId(), dossier.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private DictionaryEntryType getDictionaryEntryType(RedactionLogEntry redactionLogEntry) {
|
||||
|
||||
if (redactionLogEntry.isRecommendation() && redactionLogEntry.isFalsePositive()) {
|
||||
return DictionaryEntryType.FALSE_RECOMMENDATION;
|
||||
} else if (redactionLogEntry.isFalsePositive()) {
|
||||
return DictionaryEntryType.FALSE_POSITIVE;
|
||||
} else {
|
||||
return DictionaryEntryType.ENTRY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean revertAddToDictionary(String fileId, String dossierId, ManualRedactionEntryEntity manualRedactionToRevert) {
|
||||
|
||||
if (!manualRedactionToRevert.isAddToDictionary()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
revertAddToDictionary(manualRedactionToRevert.getValue(),
|
||||
manualRedactionToRevert.getDictionaryEntryType(),
|
||||
fileId,
|
||||
dossierId,
|
||||
manualRedactionToRevert.getTypeIdsOfModifiedDictionaries());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void revertAddToDictionary(String value, DictionaryEntryType dictionaryEntryType, String fileId, String dossierId, Set<String> typeIdsOfModifiedDictionaries) {
|
||||
|
||||
typeIdsOfModifiedDictionaries.forEach(typeId -> removeFromDictionary(typeId, value, dossierId, fileId, dictionaryEntryType));
|
||||
}
|
||||
|
||||
|
||||
public boolean revertRemoveFromDictionary(String value, String dossierId, String fileId, IdRemovalEntity idRemoval) {
|
||||
|
||||
if (!idRemoval.isRemoveFromDictionary()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
revertRemoveFromDictionary(value, dossierId, fileId, idRemoval.getTypeIdsOfModifiedDictionaries());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void revertRemoveFromDictionary(String value, String dossierId, String fileId, Set<String> typeIdsOfModifiedDictionaries) {
|
||||
|
||||
typeIdsOfModifiedDictionaries.forEach(changedTypeId -> addToDictionary(changedTypeId, value, dossierId, fileId, DictionaryEntryType.ENTRY));
|
||||
}
|
||||
|
||||
|
||||
public void validateDictionariesForDelete(ManualRequestWithRemoveFromDictionary request, RedactionLogEntry redactionLogEntry, String dossierTemplateId) {
|
||||
|
||||
if (request.isRemoveFromDictionary()) {
|
||||
var dossierTemplateTypeId = toTypeId(redactionLogEntry.getType(), dossierTemplateId);
|
||||
dictionaryManagementService.validateAddRemoveToDossierTemplateDictionary(dossierTemplateTypeId, request.isRemoveFromDictionary(), request.isRemoveFromAllDossiers());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void validateDictionariesForAdd(ManualRequestWithAddToDictionary addRedactionRequest, String value) {
|
||||
|
||||
if (addRedactionRequest.isAddToDictionary()) {
|
||||
if (addRedactionRequest.isAddToAllDossiers()) {
|
||||
// validate add to dossier template dictionaries
|
||||
dictionaryManagementService.validateAddRemoveToDossierTemplateDictionary(addRedactionRequest.getDossierTemplateTypeId());
|
||||
}
|
||||
validateDictionary(addRedactionRequest, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void validateDictionary(ManualRequestWithAddToDictionary addRedactionRequest, String value) {
|
||||
|
||||
try {
|
||||
if (!addRedactionRequest.isForceAddToDictionary() && stopwordService.isStopword(value)) {
|
||||
throw new ConflictException("The entry you are trying to add is a stopword");
|
||||
}
|
||||
dictionaryPersistenceService.getType(addRedactionRequest.getDossierTemplateTypeId());
|
||||
} catch (NotFoundException e) {
|
||||
throw new BadRequestException("Invalid type: " + addRedactionRequest.getDossierTemplateTypeId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void addToDictionary(String typeId, String value, String dossierId, String fileId, DictionaryEntryType dictionaryEntryType) {
|
||||
|
||||
try {
|
||||
log.debug("Adding entry: {} to {} for {} / {}", value, typeId, dossierId, fileId);
|
||||
dictionaryManagementService.addEntries(typeId, List.of(value), false, false, dictionaryEntryType != null ? dictionaryEntryType : DictionaryEntryType.ENTRY);
|
||||
} catch (Exception e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void removeFromDictionary(String typeId, String value, String dossierId, String fileId, DictionaryEntryType dictionaryEntryType) {
|
||||
|
||||
try {
|
||||
log.debug("Deleting entries to {} for {} / {}", typeId, dossierId, fileId);
|
||||
dictionaryManagementService.deleteEntries(typeId, List.of(value), dictionaryEntryType != null ? dictionaryEntryType : DictionaryEntryType.ENTRY);
|
||||
} catch (FeignException e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void removeResizeRedactionsWithAddToDictionary(String dossierTemplateId, String redactionLogEntryValue) {
|
||||
|
||||
var resizeRedactionsWithSameValue = resizeRedactionPersistenceService.findByAnnotationStatusAndValue(AnnotationStatus.APPROVED, redactionLogEntryValue);
|
||||
resizeRedactionsWithSameValue.forEach(resizeRedaction -> {
|
||||
var file = fileStatusPersistenceService.getStatus(resizeRedaction.getId().getFileId());
|
||||
var dossierForResizeRedaction = dossierPersistenceService.findByDossierId(file.getDossierId());
|
||||
if (!file.getWorkflowStatus().equals(WorkflowStatus.APPROVED) && dossierTemplateId.equals(dossierForResizeRedaction.getDossierTemplateId())) {
|
||||
resizeRedactionPersistenceService.hardDelete(resizeRedaction.getId().getFileId(), resizeRedaction.getId().getAnnotationId());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service;
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions;
|
||||
|
||||
import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter.convert;
|
||||
|
||||
@ -0,0 +1,407 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.google.common.hash.HashFunction;
|
||||
import com.google.common.hash.Hashing;
|
||||
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.service.AnalysisFlagsCalculationService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.CommentService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ForceRedactionPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ImageRecategorizationPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.LegalBasisChangePersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.BaseManualRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ForceRedactionRequest;
|
||||
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.ManualAddResponse;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
|
||||
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.ResizeRedactionRequest;
|
||||
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.redactionlog.RedactionLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry;
|
||||
|
||||
import feign.FeignException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class ManualRedactionService {
|
||||
|
||||
DossierPersistenceService dossierPersistenceService;
|
||||
AddRedactionPersistenceService addRedactionPersistenceService;
|
||||
RemoveRedactionPersistenceService removeRedactionPersistenceService;
|
||||
ForceRedactionPersistenceService forceRedactionPersistenceService;
|
||||
CommentService commentService;
|
||||
ImageRecategorizationPersistenceService recategorizationPersistenceService;
|
||||
LegalBasisChangePersistenceService legalBasisChangePersistenceService;
|
||||
ResizeRedactionPersistenceService resizeRedactionPersistenceService;
|
||||
FileStatusService fileStatusService;
|
||||
ManualRedactionProviderService manualRedactionProviderService;
|
||||
AnalysisFlagsCalculationService analysisFlagsCalculationService;
|
||||
RedactionLogService redactionLogService;
|
||||
DictionaryManagementService dictionaryManagementService;
|
||||
HashFunction hashFunction = Hashing.murmur3_128();
|
||||
ManualRedactionDictionaryUpdateHandler manualRedactionDictionaryUpdateHandler;
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ManualAddResponse> addAddRedaction(String dossierId, String fileId, List<AddRedactionRequest> addRedactionRequests) {
|
||||
|
||||
var response = new ArrayList<ManualAddResponse>();
|
||||
|
||||
dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
|
||||
for (AddRedactionRequest addRedactionRequest : addRedactionRequests) {
|
||||
manualRedactionDictionaryUpdateHandler.validateDictionariesForAdd(addRedactionRequest, addRedactionRequest.getValue());
|
||||
validatePositions(fileId, addRedactionRequest);
|
||||
|
||||
String annotationId = hashFunction.hashString(fileId + addRedactionRequest, StandardCharsets.UTF_8).toString();
|
||||
|
||||
addRedactionPersistenceService.insert(fileId, annotationId, addRedactionRequest);
|
||||
|
||||
Set<String> typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.handleAddToDictionaryAndReturnModifiedTypeIds(fileId, addRedactionRequest.getValue(), addRedactionRequest);
|
||||
|
||||
addRedactionPersistenceService.updateStatus(fileId,
|
||||
annotationId,
|
||||
addRedactionRequest.getStatus(),
|
||||
!typeIdsOfModifiedDictionaries.isEmpty(),
|
||||
typeIdsOfModifiedDictionaries);
|
||||
|
||||
Long commentId = commentService.addCommentAndGetId(fileId, annotationId, addRedactionRequest.getComment(), addRedactionRequest.getUser());
|
||||
|
||||
response.add(ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).build());
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
if (addRedactionRequests.stream().anyMatch(BaseManualRequest::isApproved)) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
public List<ManualAddResponse> addRemoveRedaction(String dossierId, String fileId, List<RemoveRedactionRequest> removeRedactionRequests) {
|
||||
|
||||
var response = new ArrayList<ManualAddResponse>();
|
||||
var dossier = dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
RedactionLog redactionLog = redactionLogService.getRedactionLog(dossier.getId(), fileId);
|
||||
|
||||
var requiresReAnalysis = false;
|
||||
var manualRedactions = manualRedactionProviderService.getManualRedactions(fileId);
|
||||
|
||||
//validate removing from dossier template dictionary
|
||||
|
||||
for (RemoveRedactionRequest removeRedactionRequest : removeRedactionRequests) {
|
||||
RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId());
|
||||
manualRedactionDictionaryUpdateHandler.validateDictionariesForDelete(removeRedactionRequest, redactionLogEntry, dossier.getDossierTemplateId());
|
||||
|
||||
removeRedactionPersistenceService.insert(fileId, removeRedactionRequest);
|
||||
|
||||
if (manualAddRedactionsContains(manualRedactions, removeRedactionRequest.getAnnotationId())) {
|
||||
log.info("hard delete ManualRedactions for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId());
|
||||
manualRedactionProviderService.hardDeleteManualRedactions(fileId, removeRedactionRequest.getAnnotationId());
|
||||
requiresReAnalysis = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
log.info("add removeRedaction for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId());
|
||||
|
||||
Long commentId = commentService.addCommentAndGetId(fileId,
|
||||
removeRedactionRequest.getAnnotationId(),
|
||||
removeRedactionRequest.getComment(),
|
||||
removeRedactionRequest.getUser());
|
||||
|
||||
Set<String> typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.handleRemoveFromDictionaryAndReturnModifiedTypeIds(//
|
||||
redactionLogEntry,//
|
||||
fileId,//
|
||||
dossierId, //
|
||||
dossier.getDossierTemplateId(),//
|
||||
removeRedactionRequest);
|
||||
|
||||
boolean removedFromDictionary = !typeIdsOfModifiedDictionaries.isEmpty();
|
||||
|
||||
removeRedactionPersistenceService.updateStatus(fileId,
|
||||
removeRedactionRequest.getAnnotationId(),
|
||||
removeRedactionRequest.getStatus(),
|
||||
removedFromDictionary,
|
||||
typeIdsOfModifiedDictionaries);
|
||||
|
||||
requiresReAnalysis = requiresReAnalysis || removedFromDictionary;
|
||||
|
||||
response.add(ManualAddResponse.builder().annotationId(removeRedactionRequest.getAnnotationId()).commentId(commentId).build());
|
||||
}
|
||||
|
||||
if (requiresReAnalysis) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ManualAddResponse> addForceRedaction(String dossierId, String fileId, List<ForceRedactionRequest> forceRedactionRequests) {
|
||||
|
||||
var response = new ArrayList<ManualAddResponse>();
|
||||
dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
var requiresReanalysis = false;
|
||||
|
||||
for (var forceRedactionRequest : forceRedactionRequests) {
|
||||
forceRedactionPersistenceService.insert(fileId, forceRedactionRequest);
|
||||
|
||||
Long commentId = commentService.addCommentAndGetId(fileId,
|
||||
forceRedactionRequest.getAnnotationId(),
|
||||
forceRedactionRequest.getComment(),
|
||||
forceRedactionRequest.getUser());
|
||||
|
||||
requiresReanalysis = requiresReanalysis || forceRedactionRequest.isApproved();
|
||||
response.add(ManualAddResponse.builder().annotationId(forceRedactionRequest.getAnnotationId()).commentId(commentId).build());
|
||||
}
|
||||
|
||||
if (requiresReanalysis) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ManualAddResponse> addLegalBasisChange(String dossierId, String fileId, List<LegalBasisChangeRequest> legalBasisChangeRequests) {
|
||||
|
||||
var response = new ArrayList<ManualAddResponse>();
|
||||
dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
|
||||
for (var legalBasisChangeRequest : legalBasisChangeRequests) {
|
||||
legalBasisChangePersistenceService.insert(fileId, legalBasisChangeRequest);
|
||||
|
||||
Long commentId = commentService.addCommentAndGetId(fileId,
|
||||
legalBasisChangeRequest.getAnnotationId(),
|
||||
legalBasisChangeRequest.getComment(),
|
||||
legalBasisChangeRequest.getUser());
|
||||
|
||||
response.add(ManualAddResponse.builder().annotationId(legalBasisChangeRequest.getAnnotationId()).commentId(commentId).build());
|
||||
}
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ManualAddResponse> addRecategorization(String dossierId, String fileId, List<RecategorizationRequest> recategorizationRequests) {
|
||||
|
||||
var response = new ArrayList<ManualAddResponse>();
|
||||
var requiresReanalysis = false;
|
||||
var dossier = dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId);
|
||||
for (var recategorizationRequest : recategorizationRequests) {
|
||||
RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, recategorizationRequest.getAnnotationId());
|
||||
manualRedactionDictionaryUpdateHandler.validateDictionariesForAdd(recategorizationRequest, redactionLogEntry.getValue());
|
||||
manualRedactionDictionaryUpdateHandler.validateDictionariesForDelete(recategorizationRequest, redactionLogEntry, dossier.getDossierTemplateId());
|
||||
|
||||
recategorizationPersistenceService.insert(fileId, recategorizationRequest);
|
||||
|
||||
Set<String> typeIdsOfDictionariesWithAdd = manualRedactionDictionaryUpdateHandler.handleAddToDictionaryAndReturnModifiedTypeIds(fileId, redactionLogEntry.getValue(), recategorizationRequest);
|
||||
Set<String> typeIdsOfDictionariesWithDelete = manualRedactionDictionaryUpdateHandler.handleRemoveFromDictionaryAndReturnModifiedTypeIds(redactionLogEntry,
|
||||
fileId,
|
||||
recategorizationRequest.getDossierId(),
|
||||
dossier.getDossierTemplateId(),
|
||||
recategorizationRequest);
|
||||
|
||||
recategorizationPersistenceService.updateStatus(fileId,
|
||||
recategorizationRequest.getAnnotationId(),
|
||||
AnnotationStatus.APPROVED,
|
||||
typeIdsOfDictionariesWithAdd != null,
|
||||
typeIdsOfDictionariesWithAdd,
|
||||
typeIdsOfDictionariesWithDelete);
|
||||
|
||||
Long commentId = commentService.addCommentAndGetId(fileId,
|
||||
recategorizationRequest.getAnnotationId(),
|
||||
recategorizationRequest.getComment(),
|
||||
recategorizationRequest.getUser());
|
||||
|
||||
requiresReanalysis = true;
|
||||
|
||||
response.add(ManualAddResponse.builder().annotationId(recategorizationRequest.getAnnotationId()).commentId(commentId).build());
|
||||
}
|
||||
if (requiresReanalysis) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public List<ManualAddResponse> addResizeRedaction(String dossierId, String fileId, List<ResizeRedactionRequest> resizeRedactionRequests) {
|
||||
|
||||
List<ManualAddResponse> response = new ArrayList<>();
|
||||
|
||||
RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId);
|
||||
|
||||
for (ResizeRedactionRequest resizeRedactionRequest : resizeRedactionRequests) {
|
||||
|
||||
var resizeRedaction = resizeRedactionPersistenceService.insert(fileId, resizeRedactionRequest);
|
||||
|
||||
if (resizeRedactionRequest.getComment() != null) {
|
||||
Long commentId = commentService.addCommentAndGetId(fileId,
|
||||
resizeRedactionRequest.getAnnotationId(),
|
||||
resizeRedactionRequest.getComment(),
|
||||
resizeRedactionRequest.getUser());
|
||||
response.add(ManualAddResponse.builder().annotationId(resizeRedactionRequest.getAnnotationId()).commentId(commentId).build());
|
||||
}
|
||||
|
||||
Set<String> typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.updateDictionaryForResizeRedactions(dossierId,
|
||||
fileId,
|
||||
resizeRedaction,
|
||||
getRedactionLogEntry(redactionLog, resizeRedaction.getId().getAnnotationId()));
|
||||
|
||||
resizeRedactionPersistenceService.updateStatus(resizeRedaction.getId().getFileId(),
|
||||
resizeRedaction.getId().getAnnotationId(),
|
||||
resizeRedaction.getStatus(),
|
||||
typeIdsOfModifiedDictionaries);
|
||||
}
|
||||
|
||||
if (resizeRedactionRequests.stream().anyMatch(BaseManualRequest::isApproved)) {
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
private void validatePositions(String fileId, AddRedactionRequest addRedactionRequest) {
|
||||
|
||||
var numberOfPages = fileStatusService.getStatus(fileId).getNumberOfPages();
|
||||
addRedactionRequest.getPositions().stream().filter(p -> p.getPage() > numberOfPages).findAny().ifPresent(p -> new BadRequestException("Invalid page found in the request"));
|
||||
}
|
||||
|
||||
|
||||
private void reprocess(String dossierId, String fileId) {
|
||||
|
||||
fileStatusService.setStatusReprocessForManual(dossierId, fileId, true);
|
||||
}
|
||||
|
||||
|
||||
private void removeFromDictionary(String typeId, String value, String dossierId, String fileId, DictionaryEntryType dictionaryEntryType) {
|
||||
|
||||
try {
|
||||
log.debug("Deleting entries to {} for {} / {}", typeId, dossierId, fileId);
|
||||
dictionaryManagementService.deleteEntries(typeId, List.of(value), dictionaryEntryType != null ? dictionaryEntryType : DictionaryEntryType.ENTRY);
|
||||
} catch (FeignException e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void addToDictionary(String typeId, String value, String dossierId, String fileId, DictionaryEntryType dictionaryEntryType) {
|
||||
|
||||
try {
|
||||
log.debug("Adding entry: {} to {} for {} / {}", value, typeId, dossierId, fileId);
|
||||
dictionaryManagementService.addEntries(typeId, List.of(value), false, false, dictionaryEntryType != null ? dictionaryEntryType : DictionaryEntryType.ENTRY);
|
||||
} catch (Exception e) {
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean manualAddRedactionsContains(ManualRedactions manualRedactions, String annotationId) {
|
||||
|
||||
return manualRedactions.getEntriesToAdd().stream().anyMatch(m -> annotationId.equals(m.getAnnotationId()));
|
||||
}
|
||||
|
||||
|
||||
private RedactionLogEntry getRedactionLogEntry(RedactionLog redactionLog, String annotationId) {
|
||||
|
||||
return redactionLog.getRedactionLogEntry()
|
||||
.stream()
|
||||
.filter(entry -> entry.getId().equals(annotationId))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NotFoundException("Annotation does not exist in redaction log."));
|
||||
}
|
||||
|
||||
|
||||
public ManualRedactions getManualRedactions(String fileId) {
|
||||
|
||||
return manualRedactionProviderService.getManualRedactions(fileId);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void updateProcessedDate(ManualRedactions manualRedactions) {
|
||||
|
||||
if (manualRedactions != null) {
|
||||
|
||||
if (manualRedactions.getEntriesToAdd() != null) {
|
||||
manualRedactions.getEntriesToAdd().forEach(e -> {
|
||||
if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) {
|
||||
addRedactionPersistenceService.markAsProcessed(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (manualRedactions.getIdsToRemove() != null) {
|
||||
manualRedactions.getIdsToRemove().forEach(e -> {
|
||||
if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) {
|
||||
removeRedactionPersistenceService.markAsProcessed(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (manualRedactions.getForceRedactions() != null) {
|
||||
manualRedactions.getForceRedactions().forEach(e -> {
|
||||
if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) {
|
||||
forceRedactionPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId());
|
||||
}
|
||||
});
|
||||
}
|
||||
if (manualRedactions.getImageRecategorization() != null) {
|
||||
manualRedactions.getImageRecategorization().forEach(e -> {
|
||||
if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) {
|
||||
recategorizationPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId());
|
||||
}
|
||||
});
|
||||
}
|
||||
if (manualRedactions.getResizeRedactions() != null) {
|
||||
manualRedactions.getResizeRedactions().forEach(e -> {
|
||||
if (!e.getStatus().equals(AnnotationStatus.REQUESTED) && e.getProcessedDate() == null) {
|
||||
resizeRedactionPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,380 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions;
|
||||
|
||||
import static com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource.ANNOTATION_ID;
|
||||
import static com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource.DOSSIER_ID;
|
||||
import static com.iqser.red.service.persistence.service.v1.api.external.resource.ManualRedactionResource.FILE_ID;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
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.ManualImageRecategorizationEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.AnalysisFlagsCalculationService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ForceRedactionPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ImageRecategorizationPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.LegalBasisChangePersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualImageRecategorization;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange;
|
||||
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.audit.AuditRequest;
|
||||
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.manual.ManualRedactionWrapperModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry;
|
||||
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
public class ManualRedactionUndoService {
|
||||
|
||||
ManualRedactionProviderService manualRedactionProviderService;
|
||||
AuditPersistenceService auditPersistenceService;
|
||||
FileStatusService fileStatusService;
|
||||
AnalysisFlagsCalculationService analysisFlagsCalculationService;
|
||||
ImageRecategorizationPersistenceService recategorizationPersistenceService;
|
||||
DossierPersistenceService dossierPersistenceService;
|
||||
AddRedactionPersistenceService addRedactionPersistenceService;
|
||||
RemoveRedactionPersistenceService removeRedactionPersistenceService;
|
||||
ForceRedactionPersistenceService forceRedactionPersistenceService;
|
||||
LegalBasisChangePersistenceService legalBasisChangePersistenceService;
|
||||
ResizeRedactionPersistenceService resizeRedactionPersistenceService;
|
||||
RedactionLogService redactionLogService;
|
||||
ManualRedactionDictionaryUpdateHandler manualRedactionDictionaryUpdateHandler;
|
||||
|
||||
|
||||
@Transactional
|
||||
public void undo(String dossierId, String fileId, Set<String> annotationIds) {
|
||||
|
||||
// undo the latest manual redaction for each annotationId
|
||||
ManualRedactions manualRedactions = getManualRedactions(fileId);
|
||||
|
||||
Map<String, ManualRedactionWrapperModel> manualRedactionWrappers = getLatestManualRedactionsForAnnotationIds(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);
|
||||
undoLegalBasisChange(dossierId, fileId, manualRedactionWrappers);
|
||||
undoResize(dossierId, fileId, manualRedactionWrappers);
|
||||
reprocess(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
private ManualRedactions getManualRedactions(String fileId) {
|
||||
|
||||
return manualRedactionProviderService.getManualRedactions(fileId);
|
||||
}
|
||||
|
||||
|
||||
private void reprocess(String dossierId, String fileId) {
|
||||
|
||||
fileStatusService.setStatusReprocessForManual(dossierId, fileId, true);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
.collect(Collectors.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) {
|
||||
|
||||
OffsetDateTime now = OffsetDateTime.now();
|
||||
for (var annotationId : annotationIds) {
|
||||
resizeRedactionPersistenceService.softDelete(fileId, annotationId, now);
|
||||
}
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
private void undoLegalBasisChange(String dossierId, String fileId, Map<String, ManualRedactionWrapperModel> manualRedactionWrappers) {
|
||||
|
||||
List<String> manualLegalBasisChanges = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualLegalBasisChange)
|
||||
.map(ManualRedactionWrapperModel::getId)
|
||||
.collect(Collectors.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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void deleteLegalBasisChange(String dossierId, String fileId, List<String> annotationIds) {
|
||||
|
||||
for (var annotationId : annotationIds) {
|
||||
legalBasisChangePersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
private void undoRecategorization(String dossierId, String fileId, Map<String, ManualRedactionWrapperModel> manualRedactionWrappers) {
|
||||
|
||||
List<String> manualImageRecategorizations = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualImageRecategorization)
|
||||
.map(ManualRedactionWrapperModel::getId)
|
||||
.collect(Collectors.toList());
|
||||
if (!manualImageRecategorizations.isEmpty()) {
|
||||
|
||||
deleteRecategorization(dossierId, fileId, manualImageRecategorizations);
|
||||
manualImageRecategorizations.forEach(annotationId -> auditPersistenceService.audit(AuditRequest.builder()
|
||||
.userId(KeycloakSecurity.getUserId())
|
||||
.objectId(fileId)
|
||||
.category(AuditCategory.DOCUMENT.name())
|
||||
.message("Undo of manual image 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) {
|
||||
|
||||
dossierPersistenceService.getAndValidateDossier(dossierId);
|
||||
RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId);
|
||||
|
||||
for (var annotationId : annotationIds) {
|
||||
ManualImageRecategorizationEntity recategorizationEntity = recategorizationPersistenceService.findRecategorization(fileId, annotationId);
|
||||
String originalValue = getRedactionLogEntry(redactionLog, annotationId).getValue();
|
||||
manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, recategorizationEntity.getTypeIdsOfDictionariesWithDelete());
|
||||
manualRedactionDictionaryUpdateHandler.revertAddToDictionary(originalValue, DictionaryEntryType.ENTRY, fileId, dossierId, recategorizationEntity.getTypeIdsOfDictionariesWithAdd());
|
||||
recategorizationPersistenceService.updateStatus(fileId, annotationId, AnnotationStatus.APPROVED, false, Collections.emptySet(), Collections.emptySet());
|
||||
recategorizationPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
} analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
.collect(Collectors.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) {
|
||||
|
||||
var now = OffsetDateTime.now();
|
||||
|
||||
for (var annotationId : annotationIds) {
|
||||
forceRedactionPersistenceService.softDelete(fileId, annotationId, now);
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
private void undoIdRemovals(String dossierId, String fileId, Map<String, ManualRedactionWrapperModel> manualRedactionWrappers) {
|
||||
|
||||
List<String> idRemovals = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof IdRemoval)
|
||||
.map(ManualRedactionWrapperModel::getId)
|
||||
.collect(Collectors.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);
|
||||
RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId);
|
||||
|
||||
for (String annotationId : annotationIds) {
|
||||
|
||||
IdRemovalEntity removeRedaction = removeRedactionPersistenceService.findRemoveRedaction(fileId, annotationId);
|
||||
String originalValue = getRedactionLogEntry(redactionLog, annotationId).getValue();
|
||||
boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, removeRedaction);
|
||||
removeRedactionPersistenceService.updateStatus(fileId, annotationId, removeRedaction.getStatus(), dictionaryChanged, Collections.emptySet());
|
||||
removeRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
private void undoManualRedactionEntries(String dossierId, String fileId, Map<String, ManualRedactionWrapperModel> manualRedactionWrappers) {
|
||||
|
||||
List<String> manualRedactionEntries = manualRedactionWrappers.values()
|
||||
.stream()
|
||||
.filter(manualRedactionWrapper -> manualRedactionWrapper.getItem() instanceof ManualRedactionEntry)
|
||||
.map(ManualRedactionWrapperModel::getId)
|
||||
.collect(Collectors.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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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.updateStatus(fileId, annotationId, AnnotationStatus.APPROVED, dictionaryChanged, null);
|
||||
addRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now());
|
||||
}
|
||||
|
||||
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
private RedactionLogEntry getRedactionLogEntry(RedactionLog redactionLog, String annotationId) {
|
||||
|
||||
return redactionLog.getRedactionLogEntry()
|
||||
.stream()
|
||||
.filter(entry -> entry.getId().equals(annotationId))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new NotFoundException("Annotation does not exist in redaction log."));
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private ManualRedactionWrapperModel getLatestManualRedactionForAnnotationId(ManualRedactions manualRedactions, String annotationId) {
|
||||
|
||||
final List<ManualRedactionWrapperModel> manualRedactionWrappers = new ArrayList<>();
|
||||
|
||||
manualRedactions.getEntriesToAdd()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
manualRedactions.getImageRecategorization()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
manualRedactions.getIdsToRemove()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
manualRedactions.getForceRedactions()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
manualRedactions.getLegalBasisChanges()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
manualRedactions.getResizeRedactions()
|
||||
.stream()
|
||||
.filter(item -> item.getSoftDeletedTime() == null && item.getAnnotationId().equals(annotationId))
|
||||
.forEach(item -> manualRedactionWrappers.add(new ManualRedactionWrapperModel(item.getAnnotationId(), item.getRequestDate(), item)));
|
||||
|
||||
var sortedManualRedactionWrappers = manualRedactionWrappers.stream()
|
||||
.sorted(Comparator.comparing(ManualRedactionWrapperModel::getDate, Comparator.nullsLast(Comparator.reverseOrder())))
|
||||
.toList();
|
||||
|
||||
return sortedManualRedactionWrappers.isEmpty() ? null : sortedManualRedactionWrappers.get(0);
|
||||
}
|
||||
|
||||
}
|
||||
@ -119,7 +119,7 @@ public class AddRedactionPersistenceService {
|
||||
boolean isAddOrRemoveFromDictionary,
|
||||
Set<String> typeIdsOfModifiedDictionaries) {
|
||||
|
||||
var addRedaction = manualRedactionRepository.findById(new AnnotationEntityId(annotationId, fileId))
|
||||
ManualRedactionEntryEntity addRedaction = manualRedactionRepository.findById(new AnnotationEntityId(annotationId, fileId))
|
||||
.orElseThrow(() -> new NotFoundException("Unknown file/annotation combination: " + fileId + "/" + annotationId));
|
||||
|
||||
addRedaction.setStatus(annotationStatus);
|
||||
|
||||
@ -3,6 +3,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service.persis
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -13,7 +14,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.annotati
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.ImageRecategorizationRepository;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ImageRecategorizationRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RecategorizationRequest;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -26,12 +27,13 @@ public class ImageRecategorizationPersistenceService {
|
||||
private final ImageRecategorizationRepository imageRecategorizationRepository;
|
||||
|
||||
|
||||
public void insert(String fileId, ImageRecategorizationRequest imageRecategorizationRequest) {
|
||||
public void insert(String fileId, RecategorizationRequest recategorizationRequest) {
|
||||
|
||||
ManualImageRecategorizationEntity manualImageRecategorization = new ManualImageRecategorizationEntity();
|
||||
manualImageRecategorization.setId(new AnnotationEntityId(imageRecategorizationRequest.getAnnotationId(), fileId));
|
||||
BeanUtils.copyProperties(imageRecategorizationRequest, manualImageRecategorization);
|
||||
manualImageRecategorization.setId(new AnnotationEntityId(recategorizationRequest.getAnnotationId(), fileId));
|
||||
BeanUtils.copyProperties(recategorizationRequest, manualImageRecategorization);
|
||||
manualImageRecategorization.setRequestDate(OffsetDateTime.now());
|
||||
manualImageRecategorization.setTypeId(recategorizationRequest.getDossierTemplateTypeId());
|
||||
imageRecategorizationRepository.saveAndFlush(manualImageRecategorization);
|
||||
|
||||
}
|
||||
@ -43,6 +45,25 @@ public class ImageRecategorizationPersistenceService {
|
||||
imageRecategorizationRepository.updateStatus(new AnnotationEntityId(annotationId, fileId), annotationStatus);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void updateStatus(String fileId,
|
||||
String annotationId,
|
||||
AnnotationStatus annotationStatus,
|
||||
boolean modifiedDictionary,
|
||||
Set<String> typeIdsOfDictionaryWithAdd,
|
||||
Set<String> typeIdsOfDictionaryWithDelete) {
|
||||
|
||||
ManualImageRecategorizationEntity addRedaction = imageRecategorizationRepository.findById(new AnnotationEntityId(annotationId, fileId))
|
||||
.orElseThrow(() -> new NotFoundException("Unknown file/annotation combination: " + fileId + "/" + annotationId));
|
||||
|
||||
addRedaction.setStatus(annotationStatus);
|
||||
addRedaction.setAddToDictionary(modifiedDictionary);
|
||||
addRedaction.setTypeIdsOfDictionariesWithAdd(typeIdsOfDictionaryWithAdd);
|
||||
addRedaction.setTypeIdsOfDictionariesWithDelete(typeIdsOfDictionaryWithDelete);
|
||||
|
||||
imageRecategorizationRepository.saveAndFlush(addRedaction);
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void hardDelete(String fileId, String annotationId) {
|
||||
|
||||
@ -1,550 +0,0 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service.redactionlog;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.ColorUtils;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualImageRecategorization;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange;
|
||||
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.dossiertemplate.configuration.Colors;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.Type;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.Change;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.ChangeType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.Engine;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.ManualChange;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.ManualRedactionType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.Point;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.Rectangle;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogComment;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class RedactionLogMergeService {
|
||||
|
||||
private static final String DELETED_TYPE_COLOR = "#9398a0";
|
||||
private final SectionTextService sectionTextService;
|
||||
private final FileManagementStorageService fileManagementStorageService;
|
||||
|
||||
|
||||
@Timed("redactmanager_getMergedRedactionLog")
|
||||
public RedactionLog provideRedactionLog(RedactionRequest redactionRequest) {
|
||||
|
||||
log.debug("Requested preview for: {}", redactionRequest);
|
||||
|
||||
var redactionLog = fileManagementStorageService.getRedactionLog(redactionRequest.getDossierId(), redactionRequest.getFileId());
|
||||
|
||||
if (redactionLog == null) {
|
||||
throw new NotFoundException("RedactionLog not present");
|
||||
}
|
||||
|
||||
log.debug("Loaded redaction log with computationalVersion: {}", redactionLog.getAnalysisVersion());
|
||||
var merged = mergeRedactionLogData(redactionLog,
|
||||
redactionRequest.getManualRedactions(),
|
||||
redactionRequest.getExcludedPages(),
|
||||
redactionRequest.getTypes(),
|
||||
redactionRequest.getColors());
|
||||
|
||||
merged.getRedactionLogEntry().removeIf(e -> e.isFalsePositive() && !redactionRequest.isIncludeFalsePositives());
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
|
||||
private RedactionLog mergeRedactionLogData(RedactionLog redactionLog, ManualRedactions manualRedactions, Set<Integer> excludedPages, List<Type> types, Colors colors) {
|
||||
|
||||
var skippedImportedRedactions = new HashSet<>();
|
||||
log.info("Merging Redaction log with manual redactions");
|
||||
if (manualRedactions != null) {
|
||||
|
||||
var manualRedactionWrappers = createManualRedactionWrappers(manualRedactions);
|
||||
|
||||
for (RedactionLogEntry entry : redactionLog.getRedactionLogEntry()) {
|
||||
var applicableManualRedactions = manualRedactionWrappers.stream().filter(mr -> entry.getId().equals(mr.getId())).collect(Collectors.toList());
|
||||
if (!applicableManualRedactions.isEmpty()) {
|
||||
processRedactionLogEntry(applicableManualRedactions, entry, types, colors);
|
||||
}
|
||||
|
||||
if (entry.isImported() && !entry.isRedacted()) {
|
||||
skippedImportedRedactions.add(entry.getId());
|
||||
}
|
||||
|
||||
entry.setComments(convert(manualRedactions.getComments().get(entry.getId())));
|
||||
|
||||
if (excludedPages != null && !excludedPages.isEmpty()) {
|
||||
entry.getPositions().forEach(pos -> {
|
||||
if (!isLocalManualRedaction(entry) && excludedPages.contains(pos.getPage())) {
|
||||
entry.setExcluded(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Set<String> processedIds = new HashSet<>();
|
||||
redactionLog.getRedactionLogEntry().removeIf(entry -> {
|
||||
|
||||
if (entry.getImportedRedactionIntersections() != null) {
|
||||
entry.getImportedRedactionIntersections().removeAll(skippedImportedRedactions);
|
||||
if (!entry.getImportedRedactionIntersections().isEmpty() && (!entry.isImage() || entry.isImage() && !(entry.getType().equals("image") || entry.getType()
|
||||
.equals("ocr")))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (processedIds.contains(entry.getId())) {
|
||||
log.info("Duplicate annotation found with id {}", entry.getId());
|
||||
return true;
|
||||
}
|
||||
processedIds.add(entry.getId());
|
||||
return false;
|
||||
});
|
||||
return redactionLog;
|
||||
}
|
||||
|
||||
|
||||
private boolean isLocalManualRedaction(RedactionLogEntry entry) {
|
||||
|
||||
return entry.getManualChanges() != null && entry.getManualChanges()
|
||||
.stream()
|
||||
.anyMatch(mc -> mc.getManualRedactionType() == ManualRedactionType.ADD_LOCALLY || mc.getManualRedactionType() == ManualRedactionType.RESIZE && mc.getAnnotationStatus() == AnnotationStatus.APPROVED && entry.getEngines()
|
||||
.contains(Engine.RULE) && !entry.getEngines().contains(Engine.DICTIONARY));
|
||||
|
||||
}
|
||||
|
||||
|
||||
private List<ManualRedactionWrapper> createManualRedactionWrappers(ManualRedactions manualRedactions) {
|
||||
|
||||
List<ManualRedactionWrapper> manualRedactionWrappers = new ArrayList<>();
|
||||
|
||||
manualRedactions.getImageRecategorization().forEach(item -> {
|
||||
if (item.getSoftDeletedTime() == null) {
|
||||
manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item));
|
||||
}
|
||||
});
|
||||
|
||||
manualRedactions.getIdsToRemove().forEach(item -> {
|
||||
if (item.getSoftDeletedTime() == null) {
|
||||
manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item));
|
||||
}
|
||||
});
|
||||
|
||||
manualRedactions.getForceRedactions().forEach(item -> {
|
||||
if (item.getSoftDeletedTime() == null) {
|
||||
manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item));
|
||||
}
|
||||
});
|
||||
|
||||
manualRedactions.getLegalBasisChanges().forEach(item -> {
|
||||
if (item.getSoftDeletedTime() == null) {
|
||||
manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item));
|
||||
}
|
||||
});
|
||||
|
||||
manualRedactions.getResizeRedactions().forEach(item -> {
|
||||
if (item.getSoftDeletedTime() == null) {
|
||||
manualRedactionWrappers.add(new ManualRedactionWrapper(item.getAnnotationId(), item.getRequestDate(), item));
|
||||
}
|
||||
});
|
||||
|
||||
Collections.sort(manualRedactionWrappers);
|
||||
|
||||
return manualRedactionWrappers;
|
||||
}
|
||||
|
||||
|
||||
private void processRedactionLogEntry(List<ManualRedactionWrapper> manualRedactionWrappers, RedactionLogEntry redactionLogEntry, List<Type> types, Colors colors) {
|
||||
|
||||
manualRedactionWrappers.forEach(mrw -> {
|
||||
|
||||
Object item = mrw.getItem();
|
||||
if (item instanceof ManualImageRecategorization) {
|
||||
var imageRecategorization = (ManualImageRecategorization) item;
|
||||
processManualImageRecategorization(redactionLogEntry, types, colors, imageRecategorization);
|
||||
}
|
||||
|
||||
if (item instanceof IdRemoval) {
|
||||
var manualRemoval = (IdRemoval) item;
|
||||
processIdRemoval(redactionLogEntry, types, colors, manualRemoval);
|
||||
}
|
||||
|
||||
if (item instanceof ManualForceRedaction) {
|
||||
var manualForceRedact = (ManualForceRedaction) item;
|
||||
processManualForceRedaction(redactionLogEntry, types, colors, manualForceRedact);
|
||||
}
|
||||
|
||||
if (item instanceof ManualLegalBasisChange) {
|
||||
var manualLegalBasisChange = (ManualLegalBasisChange) item;
|
||||
processManualLegalBasisChange(redactionLogEntry, types, colors, manualLegalBasisChange);
|
||||
}
|
||||
|
||||
if (item instanceof ManualResizeRedaction) {
|
||||
var manualResizeRedact = (ManualResizeRedaction) item;
|
||||
processManualResizeRedaction(redactionLogEntry, types, colors, manualResizeRedact);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void processManualImageRecategorization(RedactionLogEntry redactionLogEntry, List<Type> types, Colors colors, ManualImageRecategorization imageRecategorization) {
|
||||
|
||||
String manualOverrideReason = null;
|
||||
if (imageRecategorization.getStatus().equals(AnnotationStatus.APPROVED)) {
|
||||
|
||||
redactionLogEntry.setType(imageRecategorization.getType());
|
||||
redactionLogEntry.setSection("Image:" + redactionLogEntry.getType());
|
||||
|
||||
if (isHint(types, imageRecategorization.getType())) {
|
||||
redactionLogEntry.setRedacted(false);
|
||||
redactionLogEntry.setHint(true);
|
||||
} else {
|
||||
redactionLogEntry.setHint(false);
|
||||
}
|
||||
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", recategorized by manual override");
|
||||
} else if (imageRecategorization.getStatus().equals(AnnotationStatus.REQUESTED)) {
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to recategorize");
|
||||
redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, false, redactionLogEntry.isRedacted(), false, types));
|
||||
}
|
||||
|
||||
if (manualOverrideReason != null) {
|
||||
redactionLogEntry.setReason(manualOverrideReason);
|
||||
}
|
||||
|
||||
redactionLogEntry.getManualChanges()
|
||||
.add(ManualChange.from(imageRecategorization).withManualRedactionType(ManualRedactionType.RECATEGORIZE).withChange("type", imageRecategorization.getType()));
|
||||
}
|
||||
|
||||
|
||||
private String mergeReasonIfNecessary(String currentReason, String addition) {
|
||||
|
||||
if (currentReason != null) {
|
||||
if (!currentReason.contains(addition)) {
|
||||
return currentReason + addition;
|
||||
}
|
||||
return currentReason;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void processIdRemoval(RedactionLogEntry redactionLogEntry, List<Type> types, Colors colors, IdRemoval manualRemoval) {
|
||||
|
||||
boolean isApprovedRedaction = manualRemoval.getStatus().equals(AnnotationStatus.APPROVED);
|
||||
if (isApprovedRedaction && manualRemoval.isRemoveFromDictionary() && isBasedOnDictionaryOnly(redactionLogEntry)) {
|
||||
log.debug("Skipping merge for dictionary-modifying entry");
|
||||
} else {
|
||||
String redactionLogEntryType = redactionLogEntry.getType();
|
||||
String manualOverrideReason = null;
|
||||
if (isApprovedRedaction) {
|
||||
redactionLogEntry.setRedacted(false);
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", removed by manual override");
|
||||
redactionLogEntry.setColor(getColor(redactionLogEntryType, colors, false, redactionLogEntry.isRedacted(), true, types));
|
||||
redactionLogEntry.setHint(false);
|
||||
} else if (manualRemoval.getStatus().equals(AnnotationStatus.REQUESTED)) {
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to remove");
|
||||
redactionLogEntry.setColor(getColor(redactionLogEntryType, colors, true, redactionLogEntry.isRedacted(), false, types));
|
||||
}
|
||||
|
||||
if (manualOverrideReason != null) {
|
||||
redactionLogEntry.setReason(manualOverrideReason);
|
||||
}
|
||||
}
|
||||
|
||||
redactionLogEntry.getManualChanges()
|
||||
.add(ManualChange.from(manualRemoval)
|
||||
.withManualRedactionType(manualRemoval.isRemoveFromDictionary() ? ManualRedactionType.REMOVE_FROM_DICTIONARY : ManualRedactionType.REMOVE_LOCALLY));
|
||||
}
|
||||
|
||||
|
||||
private boolean isBasedOnDictionaryOnly(RedactionLogEntry redactionLogEntry) {
|
||||
|
||||
return redactionLogEntry.getEngines().contains(Engine.DICTIONARY) && redactionLogEntry.getEngines().size() == 1;
|
||||
}
|
||||
|
||||
|
||||
private void processManualForceRedaction(RedactionLogEntry redactionLogEntry, List<Type> types, Colors colors, ManualForceRedaction manualForceRedact) {
|
||||
|
||||
String manualOverrideReason = null;
|
||||
var dictionaryIsHint = isHint(types, redactionLogEntry.getType());
|
||||
if (manualForceRedact.getStatus().equals(AnnotationStatus.APPROVED)) {
|
||||
// Forcing a skipped hint should result in a hint
|
||||
if (dictionaryIsHint) {
|
||||
redactionLogEntry.setHint(true);
|
||||
} else {
|
||||
redactionLogEntry.setRedacted(true);
|
||||
}
|
||||
redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, false, redactionLogEntry.isRedacted(), false, types));
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", forced by manual override");
|
||||
redactionLogEntry.setLegalBasis(manualForceRedact.getLegalBasis());
|
||||
} else if (manualForceRedact.getStatus().equals(AnnotationStatus.REQUESTED)) {
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to force " + (dictionaryIsHint ? "hint" : "redact"));
|
||||
redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, true, redactionLogEntry.isRedacted(), false, types));
|
||||
redactionLogEntry.setLegalBasis(manualForceRedact.getLegalBasis());
|
||||
}
|
||||
|
||||
if (manualOverrideReason != null) {
|
||||
redactionLogEntry.setReason(manualOverrideReason);
|
||||
}
|
||||
|
||||
var manualChange = ManualChange.from(manualForceRedact).withManualRedactionType(dictionaryIsHint ? ManualRedactionType.FORCE_HINT : ManualRedactionType.FORCE_REDACT);
|
||||
|
||||
redactionLogEntry.getManualChanges().add(manualChange);
|
||||
}
|
||||
|
||||
|
||||
private void processManualLegalBasisChange(RedactionLogEntry redactionLogEntry, List<Type> types, Colors colors, ManualLegalBasisChange manualLegalBasisChange) {
|
||||
|
||||
String manualOverrideReason = null;
|
||||
if (manualLegalBasisChange.getStatus().equals(AnnotationStatus.APPROVED)) {
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", legal basis was manually changed");
|
||||
redactionLogEntry.setLegalBasis(manualLegalBasisChange.getLegalBasis());
|
||||
redactionLogEntry.setRedacted(true);
|
||||
if (manualLegalBasisChange.getSection() != null) {
|
||||
redactionLogEntry.setSection(manualLegalBasisChange.getSection());
|
||||
}
|
||||
if (redactionLogEntry.isRectangle() && manualLegalBasisChange.getValue() != null) {
|
||||
redactionLogEntry.setValue(manualLegalBasisChange.getValue());
|
||||
}
|
||||
} else if (manualLegalBasisChange.getStatus().equals(AnnotationStatus.REQUESTED)) {
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", legal basis change requested");
|
||||
redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, true, redactionLogEntry.isRedacted(), false, types));
|
||||
}
|
||||
|
||||
if (manualOverrideReason != null) {
|
||||
redactionLogEntry.setReason(manualOverrideReason);
|
||||
}
|
||||
|
||||
var manualChange = ManualChange.from(manualLegalBasisChange).withManualRedactionType(ManualRedactionType.LEGAL_BASIS_CHANGE);
|
||||
manualChange.withChange("legalBasis", manualLegalBasisChange.getLegalBasis());
|
||||
if (manualLegalBasisChange.getSection() != null) {
|
||||
manualChange.withChange("section", manualLegalBasisChange.getSection());
|
||||
}
|
||||
if (redactionLogEntry.isRectangle() && manualLegalBasisChange.getValue() != null) {
|
||||
manualChange.withChange("value", manualLegalBasisChange.getValue());
|
||||
}
|
||||
redactionLogEntry.getManualChanges().add(manualChange);
|
||||
}
|
||||
|
||||
|
||||
private void processManualResizeRedaction(RedactionLogEntry redactionLogEntry, List<Type> types, Colors colors, ManualResizeRedaction manualResizeRedact) {
|
||||
|
||||
String manualOverrideReason = null;
|
||||
if (manualResizeRedact.getStatus().equals(AnnotationStatus.APPROVED)) {
|
||||
redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, false, redactionLogEntry.isRedacted(), false, types));
|
||||
redactionLogEntry.setPositions(convertPositions(manualResizeRedact.getPositions()));
|
||||
if (!"signature".equalsIgnoreCase(redactionLogEntry.getType()) && !"logo".equalsIgnoreCase(redactionLogEntry.getType())) {
|
||||
redactionLogEntry.setValue(manualResizeRedact.getValue());
|
||||
}
|
||||
// This is for backwards compatibility, now the text after/before is calculated during reanalysis because we need to find dict entries on positions where entries are resized to smaller.
|
||||
if (manualResizeRedact.getTextBefore() != null || manualResizeRedact.getTextAfter() != null) {
|
||||
redactionLogEntry.setTextBefore(manualResizeRedact.getTextBefore());
|
||||
redactionLogEntry.setTextAfter(manualResizeRedact.getTextAfter());
|
||||
}
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", resized by manual override");
|
||||
} else if (manualResizeRedact.getStatus().equals(AnnotationStatus.REQUESTED)) {
|
||||
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to resize redact");
|
||||
redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), colors, true, redactionLogEntry.isRedacted(), false, types));
|
||||
redactionLogEntry.setPositions(convertPositions(manualResizeRedact.getPositions()));
|
||||
|
||||
// This is for backwards compatibility, now the text after/before is calculated during reanalysis because we need to find dict entries on positions where entries are resized to smaller.
|
||||
if (manualResizeRedact.getTextBefore() != null || manualResizeRedact.getTextAfter() != null) {
|
||||
redactionLogEntry.setTextBefore(manualResizeRedact.getTextBefore());
|
||||
redactionLogEntry.setTextAfter(manualResizeRedact.getTextAfter());
|
||||
}
|
||||
}
|
||||
|
||||
redactionLogEntry.setReason(manualOverrideReason);
|
||||
redactionLogEntry.getManualChanges()
|
||||
.add(ManualChange.from(manualResizeRedact).withManualRedactionType(ManualRedactionType.RESIZE).withChange("value", manualResizeRedact.getValue()));
|
||||
}
|
||||
|
||||
|
||||
public List<RedactionLogEntry> addManualAddEntries(SectionGrid sectionGrid,
|
||||
Set<ManualRedactionEntry> manualAdds,
|
||||
Map<String, List<Comment>> comments,
|
||||
Colors colors,
|
||||
List<Type> types,
|
||||
int analysisNumber) {
|
||||
|
||||
List<RedactionLogEntry> redactionLogEntries = new ArrayList<>();
|
||||
|
||||
for (ManualRedactionEntry manualRedactionEntry : manualAdds) {
|
||||
|
||||
if (shouldCreateManualEntry(manualRedactionEntry)) {
|
||||
RedactionLogEntry redactionLogEntry = createRedactionLogEntry(manualRedactionEntry, manualRedactionEntry.getAnnotationId(), colors, types, analysisNumber);
|
||||
redactionLogEntry.setPositions(convertPositions(manualRedactionEntry.getPositions()));
|
||||
redactionLogEntry.setComments(convert(comments.get(manualRedactionEntry.getAnnotationId())));
|
||||
redactionLogEntry.setTextBefore(manualRedactionEntry.getTextBefore());
|
||||
redactionLogEntry.setTextAfter(manualRedactionEntry.getTextAfter());
|
||||
|
||||
sectionTextService.handleSectionText(sectionGrid, redactionLogEntry);
|
||||
|
||||
redactionLogEntries.add(redactionLogEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return redactionLogEntries;
|
||||
}
|
||||
|
||||
|
||||
private List<RedactionLogComment> convert(List<Comment> comments) {
|
||||
|
||||
return comments == null ? null : comments.stream()
|
||||
.map(c -> new RedactionLogComment(c.getId(), c.getUser(), c.getText(), c.getAnnotationId(), c.getFileId(), c.getDate(), c.getSoftDeletedTime()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
private List<Rectangle> convertPositions(List<com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle> positions) {
|
||||
|
||||
return positions.stream()
|
||||
.map(pos -> new Rectangle(new Point(pos.getTopLeftX(), pos.getTopLeftY()), pos.getWidth(), pos.getHeight(), pos.getPage()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("PMD.UselessParentheses")
|
||||
private boolean shouldCreateManualEntry(ManualRedactionEntry manualRedactionEntry) {
|
||||
|
||||
return (!manualRedactionEntry.isAddToDictionary() && !manualRedactionEntry.isAddToDossierDictionary()) || ((manualRedactionEntry.isAddToDictionary() || manualRedactionEntry.isAddToDossierDictionary()) && manualRedactionEntry.getProcessedDate() == null);
|
||||
}
|
||||
|
||||
|
||||
private RedactionLogEntry createRedactionLogEntry(ManualRedactionEntry manualRedactionEntry, String id, Colors colors, List<Type> types, int analysisNumber) {
|
||||
|
||||
var addToDictionary = manualRedactionEntry.isAddToDictionary() || manualRedactionEntry.isAddToDossierDictionary();
|
||||
|
||||
var change = ManualChange.from(manualRedactionEntry).withManualRedactionType(addToDictionary ? ManualRedactionType.ADD_TO_DICTIONARY : ManualRedactionType.ADD_LOCALLY);
|
||||
List<ManualChange> changeList = new ArrayList<>();
|
||||
changeList.add(change);
|
||||
|
||||
return RedactionLogEntry.builder()
|
||||
.id(id)
|
||||
.color(getColorForManualAdd(manualRedactionEntry.getType(), colors, manualRedactionEntry.getStatus(), types))
|
||||
.reason(manualRedactionEntry.getReason())
|
||||
.isDictionaryEntry(manualRedactionEntry.isAddToDictionary())
|
||||
.isDossierDictionaryEntry(manualRedactionEntry.isAddToDossierDictionary())
|
||||
.legalBasis(manualRedactionEntry.getLegalBasis())
|
||||
.value(manualRedactionEntry.getValue())
|
||||
.sourceId(manualRedactionEntry.getSourceId())
|
||||
.section(manualRedactionEntry.getSection())
|
||||
.type(manualRedactionEntry.getType())
|
||||
.redacted(true)
|
||||
.isHint(false)
|
||||
.sectionNumber(-1)
|
||||
.rectangle(manualRedactionEntry.isRectangle())
|
||||
.manualChanges(changeList)
|
||||
.changes(List.of(new Change(analysisNumber + 1, ChangeType.ADDED, manualRedactionEntry.getRequestDate())))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
private float[] getColor(String type, Colors colors, boolean requested, boolean isRedaction, boolean skipped, List<Type> types) {
|
||||
|
||||
if (requested) {
|
||||
return ColorUtils.convertColor(colors.getRequestRemoveColor());
|
||||
}
|
||||
if (skipped || !isRedaction && !isHint(types, type)) {
|
||||
return ColorUtils.convertColor(colors.getSkippedColor());
|
||||
}
|
||||
return getColor(types, type);
|
||||
}
|
||||
|
||||
|
||||
private float[] getColorForManualAdd(String type, Colors colors, AnnotationStatus status, List<Type> types) {
|
||||
|
||||
if (status.equals(AnnotationStatus.REQUESTED)) {
|
||||
return ColorUtils.convertColor(colors.getRequestAddColor());
|
||||
} else if (status.equals(AnnotationStatus.DECLINED)) {
|
||||
return ColorUtils.convertColor(colors.getSkippedColor());
|
||||
}
|
||||
return getColor(types, type);
|
||||
}
|
||||
|
||||
|
||||
private float[] getColor(List<Type> types, String type) {
|
||||
|
||||
var matchingTypes = getMatchingTypes(types, type);
|
||||
Optional<Type> foundAndNotDeletedType = matchingTypes.stream().filter(t -> !isDeletedType(t)).findFirst();
|
||||
if (foundAndNotDeletedType.isPresent()) {
|
||||
return ColorUtils.convertColor(foundAndNotDeletedType.get().getHexColor());
|
||||
}
|
||||
Optional<Type> firstDeletedType = matchingTypes.stream().findFirst();
|
||||
return firstDeletedType.map(value -> ColorUtils.convertColor(value.getHexColor())).orElseGet(() -> ColorUtils.convertColor(DELETED_TYPE_COLOR));
|
||||
}
|
||||
|
||||
|
||||
boolean isHint(List<Type> types, String type) {
|
||||
|
||||
var matchingTypes = getMatchingTypes(types, type);
|
||||
Optional<Type> foundAndNotDeletedType = matchingTypes.stream().filter(t -> !isDeletedType(t)).findFirst();
|
||||
if (foundAndNotDeletedType.isPresent()) {
|
||||
return foundAndNotDeletedType.get().isHint();
|
||||
}
|
||||
Optional<Type> firstDeletedType = matchingTypes.stream().findFirst();
|
||||
return firstDeletedType.map(Type::isHint).orElse(false);
|
||||
}
|
||||
|
||||
|
||||
private List<Type> getMatchingTypes(List<Type> types, String type) {
|
||||
|
||||
return types.stream().filter(t -> t.getType().equals(type)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
private boolean isDeletedType(Type type) {
|
||||
|
||||
return type.getSoftDeletedTime() != null;
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
private static class ManualRedactionWrapper implements Comparable<ManualRedactionWrapper> {
|
||||
|
||||
private String id;
|
||||
private OffsetDateTime date;
|
||||
private Object item;
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(ManualRedactionWrapper o) {
|
||||
|
||||
return this.date.compareTo(o.date);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -8,9 +8,9 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations
|
||||
public class ManualImageRecategorizationMapper implements BiConsumer<ManualImageRecategorizationEntity, ManualImageRecategorization> {
|
||||
|
||||
@Override
|
||||
public void accept(ManualImageRecategorizationEntity manualRedactionEntryEntity, ManualImageRecategorization manualRedactionEntry) {
|
||||
public void accept(ManualImageRecategorizationEntity manualImageRecategorizationEntity, ManualImageRecategorization manualRedactionEntry) {
|
||||
|
||||
manualRedactionEntry.setType(manualRedactionEntryEntity.getTypeId().substring(0, manualRedactionEntryEntity.getTypeId().indexOf(":")));
|
||||
manualRedactionEntry.setType(manualImageRecategorizationEntity.getTypeId().substring(0, manualImageRecategorizationEntity.getTypeId().indexOf(":")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -155,4 +155,6 @@ databaseChangeLog:
|
||||
file: db/changelog/tenant/106-add-add-to-all-dossiers-to-resize-redactions.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/107-add-last-layout-processed-column.yaml
|
||||
- include:
|
||||
file: db/changelog/tenant/108-added-dictionary-changes-to-manual-recategorization.yaml
|
||||
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
databaseChangeLog:
|
||||
- changeSet:
|
||||
id: added-dictionary-changes-to-manual-recategorization
|
||||
author: kilian
|
||||
changes:
|
||||
- addColumn:
|
||||
columns:
|
||||
- column:
|
||||
name: add_to_dictionary
|
||||
type: BOOLEAN
|
||||
tableName: manual_image_recategorization
|
||||
- addColumn:
|
||||
columns:
|
||||
- column:
|
||||
name: add_to_all_dossiers
|
||||
type: BOOLEAN
|
||||
tableName: manual_image_recategorization
|
||||
- changeSet:
|
||||
id: added-dictionary-changes-to-manual-recategorization-2
|
||||
author: kilian
|
||||
changes:
|
||||
- createTable:
|
||||
columns:
|
||||
- column:
|
||||
constraints:
|
||||
nullable: false
|
||||
name: manual_image_recategorization_entity_annotation_id
|
||||
type: VARCHAR(255)
|
||||
- column:
|
||||
constraints:
|
||||
nullable: false
|
||||
name: manual_image_recategorization_entity_file_id
|
||||
type: VARCHAR(255)
|
||||
- column:
|
||||
name: type_ids_of_dictionaries_with_add
|
||||
type: VARCHAR(255)
|
||||
tableName: manual_recategorization_type_ids_of_dictionaries_with_add
|
||||
- createTable:
|
||||
columns:
|
||||
- column:
|
||||
constraints:
|
||||
nullable: false
|
||||
name: manual_image_recategorization_entity_annotation_id
|
||||
type: VARCHAR(255)
|
||||
- column:
|
||||
constraints:
|
||||
nullable: false
|
||||
name: manual_image_recategorization_entity_file_id
|
||||
type: VARCHAR(255)
|
||||
- column:
|
||||
name: type_ids_of_dictionaries_with_delete
|
||||
type: VARCHAR(255)
|
||||
tableName: manual_recategorization_type_ids_of_dictionaries_with_delete
|
||||
- changeSet:
|
||||
id: added-dictionary-changes-to-manual-recategorization-3
|
||||
author: kilian
|
||||
changes:
|
||||
- addForeignKeyConstraint:
|
||||
baseColumnNames: manual_image_recategorization_entity_annotation_id, manual_image_recategorization_entity_file_id
|
||||
baseTableName: manual_recategorization_type_ids_of_dictionaries_with_add
|
||||
constraintName: fk_manual_recategorization_to_dictionary_add
|
||||
deferrable: false
|
||||
initiallyDeferred: false
|
||||
onDelete: NO ACTION
|
||||
onUpdate: NO ACTION
|
||||
referencedColumnNames: annotation_id, file_id
|
||||
referencedTableName: manual_image_recategorization
|
||||
validate: true
|
||||
- addForeignKeyConstraint:
|
||||
baseColumnNames: manual_image_recategorization_entity_annotation_id, manual_image_recategorization_entity_file_id
|
||||
baseTableName: manual_recategorization_type_ids_of_dictionaries_with_delete
|
||||
constraintName: fk_manual_recategorization_to_dictionary_delete
|
||||
deferrable: false
|
||||
initiallyDeferred: false
|
||||
onDelete: NO ACTION
|
||||
onUpdate: NO ACTION
|
||||
referencedColumnNames: annotation_id, file_id
|
||||
referencedTableName: manual_image_recategorization
|
||||
validate: true
|
||||
@ -2,8 +2,6 @@ package com.iqser.red.service.peristence.v1.server.integration.service;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -11,9 +9,7 @@ import com.iqser.red.service.peristence.v1.server.integration.client.DictionaryC
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeValue;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors;
|
||||
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.Type;
|
||||
|
||||
@Service
|
||||
public class TypeProvider {
|
||||
@ -21,6 +17,7 @@ public class TypeProvider {
|
||||
@Autowired
|
||||
private DictionaryClient dictionaryClient;
|
||||
|
||||
|
||||
public TypeValue testAndProvideType(DossierTemplateModel dossierTemplate) {
|
||||
|
||||
return testAndProvideType(dossierTemplate, null, "test", false);
|
||||
@ -32,9 +29,13 @@ public class TypeProvider {
|
||||
return testAndProvideType(dossierTemplate, dossier, typeName, false);
|
||||
}
|
||||
|
||||
|
||||
public TypeValue testAndProvideType(DossierTemplateModel dossierTemplate, Dossier dossier, String typeName, boolean dossierDictionaryOnly) {
|
||||
|
||||
return testAndProvideType(dossierTemplate, dossier, typeName, dossierDictionaryOnly, 100);
|
||||
}
|
||||
|
||||
|
||||
public TypeValue testAndProvideType(DossierTemplateModel dossierTemplate, Dossier dossier, String typeName, boolean dossierDictionaryOnly, int rank) {
|
||||
|
||||
var type = new CreateTypeValue();
|
||||
@ -53,9 +54,9 @@ public class TypeProvider {
|
||||
type.setDossierDictionaryOnly(dossierDictionaryOnly);
|
||||
|
||||
dictionaryClient.addType(type);
|
||||
var allTypes = dictionaryClient.getAllTypes(dossierTemplate.getDossierTemplateId(),dossier != null ? dossier.getId() : null,false);
|
||||
var allTypes = dictionaryClient.getAllTypes(dossierTemplate.getDossierTemplateId(), dossier != null ? dossier.getId() : null, false);
|
||||
|
||||
var foundType =allTypes.getTypes().stream().filter(t -> t.getType().equalsIgnoreCase(typeName)).findAny();
|
||||
var foundType = allTypes.getTypes().stream().filter(t -> t.getType().equalsIgnoreCase(typeName)).findAny();
|
||||
assertThat(foundType).isPresent();
|
||||
|
||||
return foundType.get();
|
||||
|
||||
@ -1,27 +1,7 @@
|
||||
package com.iqser.red.service.peristence.v1.server.integration.tests;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.hash.HashFunction;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.*;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.*;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.*;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
|
||||
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.file.FileAttributeConfig;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus;
|
||||
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.manual.*;
|
||||
import feign.FeignException;
|
||||
import lombok.SneakyThrows;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -31,7 +11,59 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.hash.HashFunction;
|
||||
import com.google.common.hash.Hashing;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.DossierClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.DossierTemplateClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.FileAttributeClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.FileAttributeConfigClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.FileClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.FileManagementClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.ManualRedactionClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.ReanalysisClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.RedactionLogClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.UploadClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.ViewedPagesClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.TypeProvider;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.UserProvider;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributes;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributesConfig;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileUploadResult;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.PageExclusionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.PageRange;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.ViewedPagesRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
|
||||
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.file.FileAttributeConfig;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus;
|
||||
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.manual.AddCommentRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel;
|
||||
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.redactionlog.RedactionLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry;
|
||||
|
||||
import feign.FeignException;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
public class FileTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
@ -98,7 +130,6 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
|
||||
assertThat(fileClient.getDossierStatus(dossier.getId()).size()).isEqualTo(1);
|
||||
var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
|
||||
|
||||
|
||||
fileManagementClient.deleteFile(dossier.getId(), file.getId());
|
||||
|
||||
var nrOfFiles = fileClient.getSoftDeletedDossierStatus(dossier.getId()).size();
|
||||
@ -325,31 +356,38 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
var type = typeProvider.testAndProvideType(dossierTemplate, null, "manual");
|
||||
|
||||
var annotationId = "imagine_this_makes_sense";
|
||||
RedactionLog redactionLog = new RedactionLog();
|
||||
RedactionLogEntry redactionLogEntry = RedactionLogEntry.builder().type(type.getType()).id(annotationId).build();
|
||||
redactionLog.getRedactionLogEntry().add(redactionLogEntry);
|
||||
|
||||
when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog);
|
||||
|
||||
assertThat(fileClient.getDossierStatus(dossier.getId()).size()).isEqualTo(1);
|
||||
|
||||
var addRedaction = manualRedactionClient.addRedactionBulk(dossierId,
|
||||
fileId,
|
||||
Set.of(AddRedactionRequest.builder()
|
||||
.addToDictionary(true)
|
||||
.type(type.getType())
|
||||
.addToAllDossiers(true)
|
||||
.reason("1")
|
||||
.value("test")
|
||||
.legalBasis("1")
|
||||
.dictionaryEntryType(DictionaryEntryType.ENTRY)
|
||||
.build())).iterator().next();
|
||||
var addRedactionRequest = AddRedactionRequestModel.builder()
|
||||
.addToDictionary(true)
|
||||
.type(type.getType())
|
||||
.addToAllDossiers(true)
|
||||
.reason("1")
|
||||
.value("test")
|
||||
.legalBasis("1")
|
||||
.dictionaryEntryType(DictionaryEntryType.ENTRY)
|
||||
.build();
|
||||
manualRedactionClient.addRedactionBulk(dossierId, fileId, Set.of(addRedactionRequest));
|
||||
|
||||
manualRedactionClient.removeRedactionBulk(dossierId,
|
||||
fileId,
|
||||
Set.of(RemoveRedactionRequest.builder().annotationId(addRedaction.getAnnotationId()).comment("comment").removeFromDictionary(false).build()));
|
||||
Set.of(RemoveRedactionRequestModel.builder().annotationId(annotationId).comment("comment").removeFromDictionary(false).build()));
|
||||
manualRedactionClient.forceRedactionBulk(dossierId,
|
||||
fileId,
|
||||
Set.of(ForceRedactionRequest.builder().annotationId("forceRedactionAnnotation").comment("comment").legalBasis("1").build()));
|
||||
manualRedactionClient.legalBasisChangeBulk(dossierId,
|
||||
Set.of(ForceRedactionRequestModel.builder().annotationId("forceRedactionAnnotation").comment("comment").legalBasis("1").build()));
|
||||
manualRedactionClient.legalBasisChangeBulk(dossierId,
|
||||
fileId,
|
||||
Set.of(LegalBasisChangeRequest.builder().annotationId("legalBasisChangeAnnotation").comment("comment").legalBasis("1").build()));
|
||||
manualRedactionClient.recategorizeImageBulk(dossierId,
|
||||
Set.of(LegalBasisChangeRequestModel.builder().annotationId("legalBasisChangeAnnotation").comment("comment").legalBasis("1").build()));
|
||||
manualRedactionClient.recategorizeBulk(dossierId,
|
||||
fileId,
|
||||
Set.of(ImageRecategorizationRequest.builder().annotationId("imageRecategorizationAnnotation").comment("comment").type("new-type").build()));
|
||||
Set.of(RecategorizationRequestModel.builder().annotationId(annotationId).comment("comment").type("new-type").build()));
|
||||
|
||||
var loadedFile = fileClient.getFileStatus(dossierId, fileId);
|
||||
|
||||
@ -396,20 +434,19 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
var addRedaction = manualRedactionClient.addRedactionBulk(dossierId,
|
||||
fileId,
|
||||
Set.of(AddRedactionRequest.builder()
|
||||
Set.of(AddRedactionRequestModel.builder()
|
||||
.addToDictionary(true)
|
||||
.addToAllDossiers(true)
|
||||
.comment(new AddCommentRequest("comment"))
|
||||
.comment(new AddCommentRequestModel("comment"))
|
||||
.type(type.getType())
|
||||
.reason("1")
|
||||
.value("test")
|
||||
.legalBasis("1")
|
||||
.dictionaryEntryType(DictionaryEntryType.ENTRY)
|
||||
.dictionaryEntryType(DictionaryEntryType.ENTRY)
|
||||
.build())).iterator().next();
|
||||
|
||||
var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
|
||||
|
||||
|
||||
reanalysisClient.toggleExclusion(dossier.getId(), file.getId(), true);
|
||||
loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
|
||||
assertThat(loadedFile.isExcluded()).isTrue();
|
||||
@ -433,7 +470,6 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
|
||||
var file = fileTesterAndProvider.testAndProvideFile(dossier, fileName);
|
||||
String fileId = file.getId();
|
||||
|
||||
|
||||
var type = typeProvider.testAndProvideType(dossierTemplate, null, "manual");
|
||||
|
||||
assertThat(fileClient.getDossierStatus(dossier.getId()).size()).isEqualTo(1);
|
||||
@ -510,6 +546,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFile6034SetUnderReview() {
|
||||
|
||||
@ -537,17 +574,15 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
assertThat(actualMessage).contains(expectedMessage);
|
||||
|
||||
|
||||
exception = Assertions.assertThrows(FeignException.BadRequest.class, () -> {
|
||||
fileClient.setStatusUnderReview(dossier.getId(), file.getId(), user2);
|
||||
});
|
||||
|
||||
expectedMessage = "User must be dossier member";
|
||||
actualMessage = exception.getMessage();
|
||||
actualMessage = exception.getMessage();
|
||||
|
||||
assertThat(actualMessage).contains(expectedMessage);
|
||||
|
||||
|
||||
fileClient.setStatusUnderReview(dossier.getId(), file.getId(), altUserId);
|
||||
loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId());
|
||||
assertThat(loadedFile.getWorkflowStatus()).isEqualTo(WorkflowStatus.UNDER_REVIEW);
|
||||
@ -556,6 +591,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
|
||||
assertThat(loadedFile.getLastApprover()).isNull();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
public void testUploadFileIsInOcrProcessingWithOcrByDefaultFlagTrue() {
|
||||
|
||||
@ -13,12 +13,14 @@ import com.iqser.red.service.persistence.management.v1.processor.service.Redacti
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.redactionlog.RedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.Dictionary;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
|
||||
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.manual.AddRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel;
|
||||
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.ResizeRedactionRequestModel;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry;
|
||||
import feign.FeignException;
|
||||
@ -105,12 +107,12 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog);
|
||||
|
||||
when(redactionLogMergeService.provideRedactionLog(Mockito.any())).thenReturn(redactionLog);
|
||||
when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog);
|
||||
|
||||
Assertions.assertThrows(FeignException.Forbidden.class,
|
||||
() -> manualRedactionClient.removeRedactionBulk(dossier.getId(),
|
||||
file.getId(),
|
||||
Set.of(RemoveRedactionRequest.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())));//.get(0);
|
||||
Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())));//.get(0);
|
||||
|
||||
var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null);
|
||||
assertThat(dossierTemplateDictionary.getEntries().size()).isZero();
|
||||
@ -131,7 +133,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
manualRedactionClient.addRedactionBulk(dossier.getId(),
|
||||
file.getId(),
|
||||
Set.of(AddRedactionRequest.builder()
|
||||
Set.of(AddRedactionRequestModel.builder()
|
||||
.positions(List.of(Rectangle.builder().topLeftY(1).topLeftX(1).height(1).width(1).build()))
|
||||
.section("section test")
|
||||
.addToDictionary(true)
|
||||
@ -166,7 +168,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
manualRedactionClient.addRedactionBulk(dossier.getId(),
|
||||
file.getId(),
|
||||
Set.of(AddRedactionRequest.builder()
|
||||
Set.of(AddRedactionRequestModel.builder()
|
||||
.positions(List.of(Rectangle.builder().topLeftY(1).topLeftX(1).height(1).width(1).build()))
|
||||
.section("section test")
|
||||
.addToDictionary(true)
|
||||
@ -201,7 +203,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
manualRedactionClient.addRedactionBulk(dossier.getId(),
|
||||
file.getId(),
|
||||
Set.of(AddRedactionRequest.builder()
|
||||
Set.of(AddRedactionRequestModel.builder()
|
||||
.positions(List.of(Rectangle.builder().topLeftY(1).topLeftX(1).height(1).width(1).build()))
|
||||
.section("section test")
|
||||
.addToDictionary(true)
|
||||
@ -238,10 +240,10 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getDossierId(), DictionaryEntryType.ENTRY);
|
||||
|
||||
var dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
|
||||
Dictionary dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker", "Darth Vader");
|
||||
|
||||
var dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId());
|
||||
Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId());
|
||||
assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker");
|
||||
|
||||
var redactionLog = new RedactionLog(1,
|
||||
@ -254,11 +256,11 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog);
|
||||
|
||||
when(redactionLogMergeService.provideRedactionLog(Mockito.any())).thenReturn(redactionLog);
|
||||
when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog);
|
||||
|
||||
manualRedactionClient.removeRedactionBulk(dossier.getId(),
|
||||
file.getId(),
|
||||
Set.of(RemoveRedactionRequest.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())).get(0);
|
||||
Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build()));
|
||||
|
||||
dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Darth Vader");
|
||||
@ -302,11 +304,11 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog);
|
||||
|
||||
when(redactionLogMergeService.provideRedactionLog(Mockito.any())).thenReturn(redactionLog);
|
||||
when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog);
|
||||
|
||||
manualRedactionClient.removeRedactionBulk(dossier.getId(),
|
||||
file.getId(),
|
||||
Set.of(RemoveRedactionRequest.builder().annotationId("AnnotationId").removeFromDictionary(true).build())).get(0);
|
||||
Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).build())).get(0);
|
||||
|
||||
var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null);
|
||||
|
||||
@ -343,11 +345,11 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog);
|
||||
|
||||
when(redactionLogMergeService.provideRedactionLog(Mockito.any())).thenReturn(redactionLog);
|
||||
when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog);
|
||||
|
||||
manualRedactionClient.removeRedactionBulk(dossier.getId(),
|
||||
file.getId(),
|
||||
Set.of(RemoveRedactionRequest.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())).get(0);
|
||||
Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())).get(0);
|
||||
|
||||
var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null);
|
||||
assertThat(dossierDictionary.getEntries().size()).isEqualTo(1);
|
||||
@ -375,7 +377,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
var userId = userProvider.getUserId();
|
||||
|
||||
var redactionDos = AddRedactionRequest.builder()
|
||||
var redactionDos = AddRedactionRequestModel.builder()
|
||||
.positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
|
||||
.section("section test")
|
||||
.addToDictionary(true)
|
||||
@ -389,7 +391,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
.sourceId("SourceId")
|
||||
.build();
|
||||
|
||||
var redactionDosTempDict = AddRedactionRequest.builder()
|
||||
var redactionDosTempDict = AddRedactionRequestModel.builder()
|
||||
.positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
|
||||
.section("section test")
|
||||
.addToDictionary(true)
|
||||
@ -427,8 +429,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1);
|
||||
var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build();
|
||||
when(redactionLogMergeService.provideRedactionLog(redactionRequest1)).thenReturn(redactionLog1);
|
||||
when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId(), true, true)).thenReturn(redactionLog1);
|
||||
when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1);
|
||||
|
||||
var redactionLog2 = new RedactionLog(1,
|
||||
1,
|
||||
@ -445,11 +446,10 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2);
|
||||
var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build();
|
||||
when(redactionLogMergeService.provideRedactionLog(redactionRequest2)).thenReturn(redactionLog2);
|
||||
when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2);
|
||||
when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2);
|
||||
|
||||
// resize redaction in dossier 1
|
||||
var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequest.builder()
|
||||
var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder()
|
||||
.annotationId(addRedactions.get(0).getAnnotationId())
|
||||
.comment("resized dossier redaction")
|
||||
.value("test redaction in dossier dictionary")
|
||||
@ -524,7 +524,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
var userId = userProvider.getUserId();
|
||||
|
||||
var redactionDos = AddRedactionRequest.builder()
|
||||
var redactionDos = AddRedactionRequestModel.builder()
|
||||
.positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
|
||||
.section("section test")
|
||||
.addToDictionary(true)
|
||||
@ -538,7 +538,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
.sourceId("SourceId")
|
||||
.build();
|
||||
|
||||
var redactionDosTempDict = AddRedactionRequest.builder()
|
||||
var redactionDosTempDict = AddRedactionRequestModel.builder()
|
||||
.positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
|
||||
.section("section test")
|
||||
.addToDictionary(true)
|
||||
@ -576,8 +576,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1);
|
||||
var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build();
|
||||
when(redactionLogMergeService.provideRedactionLog(redactionRequest1)).thenReturn(redactionLog1);
|
||||
when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId(), true, true)).thenReturn(redactionLog1);
|
||||
when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1);
|
||||
|
||||
var redactionLog2 = new RedactionLog(1,
|
||||
1,
|
||||
@ -594,11 +593,10 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2);
|
||||
var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build();
|
||||
when(redactionLogMergeService.provideRedactionLog(redactionRequest2)).thenReturn(redactionLog2);
|
||||
when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2);
|
||||
when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2);
|
||||
|
||||
// resize redaction in dossier 1
|
||||
var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequest.builder()
|
||||
var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder()
|
||||
.annotationId(addRedactions.get(0).getAnnotationId())
|
||||
.comment("resized dossier redaction")
|
||||
.value("test redaction in dossier")
|
||||
@ -676,7 +674,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
var userId = userProvider.getUserId();
|
||||
|
||||
var redactionDos = AddRedactionRequest.builder()
|
||||
var redactionDos = AddRedactionRequestModel.builder()
|
||||
.positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
|
||||
.section("section test")
|
||||
.addToDictionary(true)
|
||||
@ -690,7 +688,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
.sourceId("SourceId")
|
||||
.build();
|
||||
|
||||
var redactionDosTempDict = AddRedactionRequest.builder()
|
||||
var redactionDosTempDict = AddRedactionRequestModel.builder()
|
||||
.positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
|
||||
.section("section test")
|
||||
.addToDictionary(true)
|
||||
@ -727,8 +725,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1);
|
||||
var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build();
|
||||
when(redactionLogMergeService.provideRedactionLog(redactionRequest1)).thenReturn(redactionLog1);
|
||||
when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId(), true, true)).thenReturn(redactionLog1);
|
||||
when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1);
|
||||
|
||||
var redactionLog2 = new RedactionLog(1,
|
||||
1,
|
||||
@ -745,11 +742,10 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2);
|
||||
var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build();
|
||||
when(redactionLogMergeService.provideRedactionLog(redactionRequest2)).thenReturn(redactionLog2);
|
||||
when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2);
|
||||
when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2);
|
||||
|
||||
// resize redaction in dossier dict
|
||||
var resizeRedactionDosTemp = ResizeRedactionRequest.builder()
|
||||
var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder()
|
||||
.annotationId(addRedactions.get(1).getAnnotationId())
|
||||
.comment("resized dossier template redaction")
|
||||
.value("test redaction in dossier template dictionary")
|
||||
@ -824,7 +820,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
var userId = userProvider.getUserId();
|
||||
|
||||
var redactionDos = AddRedactionRequest.builder()
|
||||
var redactionDos = AddRedactionRequestModel.builder()
|
||||
.positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
|
||||
.section("section test")
|
||||
.addToDictionary(true)
|
||||
@ -838,7 +834,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
.sourceId("SourceId")
|
||||
.build();
|
||||
|
||||
var redactionDosTempDict = AddRedactionRequest.builder()
|
||||
var redactionDosTempDict = AddRedactionRequestModel.builder()
|
||||
.positions(List.of(Rectangle.builder().page(1).topLeftY(1).topLeftX(1).height(1).width(1).build()))
|
||||
.section("section test")
|
||||
.addToDictionary(true)
|
||||
@ -875,8 +871,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1);
|
||||
var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build();
|
||||
when(redactionLogMergeService.provideRedactionLog(redactionRequest1)).thenReturn(redactionLog1);
|
||||
when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId(), true, true)).thenReturn(redactionLog1);
|
||||
when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1);
|
||||
|
||||
var redactionLog2 = new RedactionLog(1,
|
||||
1,
|
||||
@ -893,11 +888,10 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2);
|
||||
var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build();
|
||||
when(redactionLogMergeService.provideRedactionLog(redactionRequest2)).thenReturn(redactionLog2);
|
||||
when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId(), true, true)).thenReturn(redactionLog2);
|
||||
when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2);
|
||||
|
||||
// resize redaction in dossier dict
|
||||
var resizeRedactionDosTemp = ResizeRedactionRequest.builder()
|
||||
var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder()
|
||||
.annotationId(addRedactions.get(1).getAnnotationId())
|
||||
.comment("resized dossier template redaction")
|
||||
.value("test redaction in dossier template")
|
||||
@ -956,4 +950,73 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
|
||||
assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManualRecategorizeAndUndo() {
|
||||
|
||||
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.getDossierId(), 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.getDossierId());
|
||||
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.getDossierId());
|
||||
assertThat(dossierDictionary2.getEntries()).isEmpty();
|
||||
|
||||
var annotationId = "AnnotationId";
|
||||
var redactionLog = new RedactionLog(1,
|
||||
1,
|
||||
List.of(RedactionLogEntry.builder().id(annotationId).type(type.getType()).value(lukeSkywalker).isDictionaryEntry(true).build()),
|
||||
null,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog);
|
||||
|
||||
when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog);
|
||||
|
||||
manualRedactionClient.recategorizeBulk(dossier.getId(),
|
||||
file.getId(),
|
||||
Set.of(RecategorizationRequestModel.builder().type(type2.getType()).annotationId(annotationId).addToDictionary(true).addToAllDossiers(true).build()));
|
||||
|
||||
dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(darthVader);
|
||||
dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId());
|
||||
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.getDossierId());
|
||||
assertThat(dossierDictionary2.getEntries()).isEmpty();
|
||||
|
||||
manualRedactionClient.undo(dossier.getDossierId(), file.getFileId(), Set.of(annotationId));
|
||||
|
||||
dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader);
|
||||
dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId());
|
||||
assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker);
|
||||
|
||||
dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null);
|
||||
assertThat(dossierTemplateDictionary2.getEntries()).isEmpty();
|
||||
dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId());
|
||||
assertThat(dossierDictionary2.getEntries()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
package com.iqser.red.service.peristence.v1.server.integration.tests;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.iqser.red.service.peristence.v1.server.integration.client.RedactionLogClient;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider;
|
||||
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.FilteredRedactionLogRequest;
|
||||
|
||||
public class RedactionLogTest extends AbstractPersistenceServerServiceTest {
|
||||
|
||||
@Autowired
|
||||
private FileTesterAndProvider fileTesterAndProvider;
|
||||
|
||||
@Autowired
|
||||
private DossierTesterAndProvider dossierTesterAndProvider;
|
||||
|
||||
@Autowired
|
||||
private RedactionLogClient redactionLogClient;
|
||||
|
||||
|
||||
@Test
|
||||
public void testRedactionLog() {
|
||||
|
||||
var dossier = dossierTesterAndProvider.provideTestDossier();
|
||||
var file = fileTesterAndProvider.testAndProvideFile(dossier);
|
||||
|
||||
assertThat(redactionLogClient.getSectionGrid(dossier.getId(), file.getId())).isNotNull();
|
||||
assertThat(redactionLogClient.getRedactionLog(dossier.getId(), file.getId(), null, true, false)).isNotNull();
|
||||
assertThat(redactionLogClient.getRedactionLog(dossier.getId(), file.getId(), null, false, false)).isNotNull();
|
||||
assertThat(redactionLogClient.getFilteredRedactionLog(dossier.getId(),
|
||||
file.getId(),
|
||||
FilteredRedactionLogRequest.builder()
|
||||
.excludedTypes(null)
|
||||
.withManualRedactions(true)
|
||||
.includeFalsePositives(false)
|
||||
.specifiedDate(OffsetDateTime.now().minusDays(30))
|
||||
.build())).isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
@ -57,6 +57,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.configur
|
||||
import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.ApplicationConfigService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ApplicationConfigRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.AuditRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DigitalSignatureRepository;
|
||||
@ -87,7 +88,6 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.EntryRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalsePositiveEntryRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalseRecommendationEntryRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.redactionlog.RedactionLogMergeService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.ApplicationConfig;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
|
||||
@ -123,7 +123,7 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
@MockBean
|
||||
protected SearchClient searchClient;
|
||||
@MockBean
|
||||
protected RedactionLogMergeService redactionLogMergeService;
|
||||
protected RedactionLogService redactionLogService;
|
||||
@MockBean
|
||||
protected PDFTronClient pdfTronRedactionClient;
|
||||
@Autowired
|
||||
@ -277,7 +277,7 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
// doNothing().when(pdfTronRedactionClient).testDigitalCurrentSignature(Mockito.any());
|
||||
|
||||
when(amqpAdmin.getQueueInfo(Mockito.any())).thenReturn(null);
|
||||
when(redactionLogMergeService.provideRedactionLog(Mockito.any())).thenReturn(new RedactionLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0));
|
||||
when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(new RedactionLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0));
|
||||
when(redactionClient.testRules(Mockito.anyString())).thenReturn(DroolsSyntaxValidation.builder().compiled(true).droolsSyntaxErrorMessages(Collections.emptyList()).build());
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ import lombok.NoArgsConstructor;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class AddRedactionRequest {
|
||||
public class AddRedactionRequest implements ManualRequestWithAddToDictionary {
|
||||
|
||||
private String user;
|
||||
private String dossierTemplateTypeId;
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations;
|
||||
|
||||
public interface BaseManualRequest {
|
||||
|
||||
AnnotationStatus getStatus();
|
||||
|
||||
|
||||
default boolean isApproved() {
|
||||
|
||||
return getStatus().equals(AnnotationStatus.APPROVED);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,7 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.shared.model.manual;
|
||||
package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
@ -9,10 +12,8 @@ import lombok.NoArgsConstructor;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ImageRecategorizationRequest {
|
||||
public class Comments {
|
||||
|
||||
private String annotationId;
|
||||
private String type;
|
||||
private String comment;
|
||||
Map<String, List<Comment>> comments;
|
||||
|
||||
}
|
||||
@ -9,7 +9,7 @@ import lombok.NoArgsConstructor;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ForceRedactionRequest {
|
||||
public class ForceRedactionRequest implements BaseManualRequest {
|
||||
|
||||
private String annotationId;
|
||||
private String user;
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ImageRecategorizationRequest {
|
||||
|
||||
private String annotationId;
|
||||
private String user;
|
||||
private AnnotationStatus status;
|
||||
private String typeId;
|
||||
private String comment;
|
||||
private int page;
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType;
|
||||
|
||||
public interface ManualRequestWithAddToDictionary extends BaseManualRequest {
|
||||
|
||||
String getDossierId();
|
||||
|
||||
|
||||
boolean isAddToDictionary();
|
||||
|
||||
|
||||
boolean isAddToAllDossiers();
|
||||
|
||||
|
||||
boolean isForceAddToDictionary();
|
||||
|
||||
|
||||
String getDossierTemplateTypeId();
|
||||
|
||||
|
||||
DictionaryEntryType getDictionaryEntryType();
|
||||
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations;
|
||||
|
||||
public interface ManualRequestWithRemoveFromDictionary extends BaseManualRequest {
|
||||
|
||||
String getAnnotationId();
|
||||
|
||||
|
||||
boolean isRemoveFromDictionary();
|
||||
|
||||
|
||||
boolean isRemoveFromAllDossiers();
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations;
|
||||
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public class RecategorizationRequest implements ManualRequestWithAddToDictionary, ManualRequestWithRemoveFromDictionary {
|
||||
|
||||
String annotationId;
|
||||
String user;
|
||||
AnnotationStatus status;
|
||||
String dossierTemplateTypeId;
|
||||
String dossierId;
|
||||
String comment;
|
||||
int page;
|
||||
boolean addToDictionary;
|
||||
boolean addToAllDossiers;
|
||||
private DictionaryEntryType dictionaryEntryType;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isForceAddToDictionary() {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRemoveFromDictionary() {
|
||||
|
||||
return addToDictionary;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isRemoveFromAllDossiers() {
|
||||
|
||||
return addToAllDossiers;
|
||||
}
|
||||
|
||||
}
|
||||
@ -9,7 +9,7 @@ import lombok.NoArgsConstructor;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class RemoveRedactionRequest {
|
||||
public class RemoveRedactionRequest implements ManualRequestWithRemoveFromDictionary {
|
||||
|
||||
private String annotationId;
|
||||
private String user;
|
||||
|
||||
@ -12,7 +12,7 @@ import lombok.NoArgsConstructor;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ResizeRedactionRequest {
|
||||
public class ResizeRedactionRequest implements BaseManualRequest{
|
||||
|
||||
private String annotationId;
|
||||
private String user;
|
||||
|
||||
@ -10,7 +10,7 @@ import lombok.NonNull;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class AddCommentRequest {
|
||||
public class AddCommentRequestModel {
|
||||
|
||||
@NonNull
|
||||
private String text;
|
||||
@ -16,7 +16,7 @@ import lombok.NonNull;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class AddRedactionRequest {
|
||||
public class AddRedactionRequestModel {
|
||||
|
||||
@NonNull
|
||||
private String type;
|
||||
@ -36,7 +36,7 @@ public class AddRedactionRequest {
|
||||
@Builder.Default
|
||||
private List<Rectangle> positions = new ArrayList<>();
|
||||
|
||||
private AddCommentRequest comment;
|
||||
private AddCommentRequestModel comment;
|
||||
|
||||
private boolean forceAddToDictionary;
|
||||
|
||||
@ -7,7 +7,7 @@ import lombok.NoArgsConstructor;
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ApproveRequest {
|
||||
public class ApproveRequestModel {
|
||||
|
||||
private boolean addOrRemoveFromDictionary;
|
||||
|
||||
@ -10,7 +10,7 @@ import lombok.NonNull;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ForceRedactionRequest {
|
||||
public class ForceRedactionRequestModel {
|
||||
|
||||
@NonNull
|
||||
private String annotationId;
|
||||
@ -10,7 +10,7 @@ import lombok.NonNull;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class LegalBasisChangeRequest {
|
||||
public class LegalBasisChangeRequestModel {
|
||||
|
||||
@NonNull
|
||||
private String annotationId;
|
||||
@ -7,7 +7,7 @@ import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ManualRedactionWrapper implements Comparable<ManualRedactionWrapper> {
|
||||
public class ManualRedactionWrapperModel implements Comparable<ManualRedactionWrapperModel> {
|
||||
|
||||
private String id;
|
||||
private OffsetDateTime date;
|
||||
@ -15,7 +15,7 @@ public class ManualRedactionWrapper implements Comparable<ManualRedactionWrapper
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(ManualRedactionWrapper o) {
|
||||
public int compareTo(ManualRedactionWrapperModel o) {
|
||||
|
||||
// Descending
|
||||
return o.date.compareTo(this.date);
|
||||
@ -0,0 +1,23 @@
|
||||
package com.iqser.red.service.persistence.service.v1.api.shared.model.manual;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE)
|
||||
public class RecategorizationRequestModel {
|
||||
|
||||
String annotationId;
|
||||
String type;
|
||||
String comment;
|
||||
boolean addToDictionary;
|
||||
boolean addToAllDossiers;
|
||||
|
||||
}
|
||||
@ -10,7 +10,7 @@ import lombok.NonNull;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class RemoveRedactionRequest {
|
||||
public class RemoveRedactionRequestModel {
|
||||
|
||||
@NonNull
|
||||
private String annotationId;
|
||||
@ -15,7 +15,7 @@ import lombok.NonNull;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ResizeRedactionRequest {
|
||||
public class ResizeRedactionRequestModel {
|
||||
|
||||
@NonNull
|
||||
private String annotationId;
|
||||
Loading…
x
Reference in New Issue
Block a user