RED-8615: Revert and change the current behaviour of manualChanges #368

Merged
kilian.schuettler1 merged 2 commits from RED-8615-bp into release/2.349.x 2024-02-28 09:55:19 +01:00
40 changed files with 1060 additions and 296 deletions

View File

@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
import com.iqser.red.service.persistence.management.v1.processor.service.CommentService;
import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService;
@ -99,12 +100,12 @@ public class ManualRedactionController implements ManualRedactionResource {
accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId);
auditPersistenceService.audit(AuditRequest.builder()
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Comment was removed.")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
.build());
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Comment was removed.")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
.build());
commentService.deleteComment(fileId, List.of(Long.valueOf(commentId)));
}
@ -114,11 +115,12 @@ public class ManualRedactionController implements ManualRedactionResource {
@PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')")
public ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed) {
@RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed,
@RequestParam(value = "includeDictChanges", required = false, defaultValue = TRUE) boolean includeDictChanges) {
accessControlService.checkDossierExistenceAndViewPermissionsToDossier(dossierId);
accessControlService.validateFileResourceExistence(fileId);
return manualRedactionService.getManualRedactions(fileId, unprocessed);
return manualRedactionService.getManualRedactions(fileId, ManualChangesQueryOptions.builder().includeOnlyUnprocessed(unprocessed).includeDictChanges(includeDictChanges).build());
}
@ -149,12 +151,12 @@ public class ManualRedactionController implements ManualRedactionResource {
var response = commentService.addComment(fileId, annotationId, CommentRequest.builder().user(KeycloakSecurity.getUserId()).text(addCommentRequest.getText()).build());
auditPersistenceService.audit(AuditRequest.builder()
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Comment was added.")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
.build());
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Comment was added.")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId))
.build());
return new CommentResponse(String.valueOf(response.getId()));
}
@ -169,7 +171,8 @@ public class ManualRedactionController implements ManualRedactionResource {
var dossier = dossierManagementService.getDossierById(dossierId, false, false);
accessControlService.checkAccessPermissionsToDossier(dossierId);
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
if (addRedactionRequests.stream().anyMatch(AddRedactionRequestModel::isAddToAllDossiers)) {
if (addRedactionRequests.stream()
.anyMatch(AddRedactionRequestModel::isAddToAllDossiers)) {
accessControlService.verifyUserIsApprover(dossierId);
} else {
accessControlService.verifyUserIsMemberOrApprover(dossierId);
@ -179,12 +182,12 @@ public class ManualRedactionController implements ManualRedactionResource {
List<ManualAddResponse> responseList = manualRedactionService.addAddRedaction(dossierId, fileId, requests);
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Manual redaction was added.")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Manual redaction was added.")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
return responseList;
}
@ -199,22 +202,27 @@ public class ManualRedactionController implements ManualRedactionResource {
var dossier = dossierManagementService.getDossierById(dossierId, false, false);
accessControlService.checkAccessPermissionsToDossier(dossierId);
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
if (removeRedactionRequests.stream().anyMatch(RemoveRedactionRequestModel::isRemoveFromAllDossiers)) {
if (removeRedactionRequests.stream()
.anyMatch(RemoveRedactionRequestModel::isRemoveFromAllDossiers)) {
accessControlService.verifyUserIsApprover(dossierId);
} else {
accessControlService.verifyUserIsMemberOrApprover(dossierId);
}
List<RemoveRedactionRequest> requests = manualRedactionMapper.toRemoveRedactionRequestList(dossierId, fileId, dossier.getDossierTemplateId(), removeRedactionRequests, includeUnprocessed);
List<RemoveRedactionRequest> requests = manualRedactionMapper.toRemoveRedactionRequestList(dossierId,
fileId,
dossier.getDossierTemplateId(),
removeRedactionRequests,
includeUnprocessed);
List<ManualAddResponse> responseList = manualRedactionService.addRemoveRedaction(dossierId, fileId, requests);
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Redaction was manually removed")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Redaction was manually removed")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
return responseList;
}
@ -233,12 +241,12 @@ public class ManualRedactionController implements ManualRedactionResource {
List<ManualAddResponse> responseList = manualRedactionService.addForceRedaction(dossierId, fileId, requests);
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Skipped redaction was forced to be redacted")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Skipped redaction was forced to be redacted")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
return responseList;
}
@ -258,12 +266,12 @@ public class ManualRedactionController implements ManualRedactionResource {
List<ManualAddResponse> responseList = manualRedactionService.addLegalBasisChange(dossierId, fileId, requests);
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Legal basis reason was changed")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Legal basis reason was changed")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
return responseList;
}
@ -280,17 +288,21 @@ public class ManualRedactionController implements ManualRedactionResource {
accessControlService.verifyFileIsNotApproved(dossierId, fileId);
accessControlService.verifyUserIsMemberOrApprover(dossierId);
List<RecategorizationRequest> requests = manualRedactionMapper.toRecategorizationRequestList(dossierId, fileId, dossier.getDossierTemplateId(), recategorizationRequests, includeUnprocessed);
List<RecategorizationRequest> requests = manualRedactionMapper.toRecategorizationRequestList(dossierId,
fileId,
dossier.getDossierTemplateId(),
recategorizationRequests,
includeUnprocessed);
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("Entity was recategorized.")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Entity was recategorized.")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
return responseList;
}
@ -310,12 +322,12 @@ public class ManualRedactionController implements ManualRedactionResource {
List<ManualAddResponse> responseList = manualRedactionService.addResizeRedaction(dossierId, fileId, requests, includeUnprocessed);
responseList.forEach(response -> auditPersistenceService.audit(AuditRequest.builder()
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Skipped redaction was resized to be redacted")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
.userId(KeycloakSecurity.getUserId())
.objectId(fileId)
.category(AuditCategory.DOCUMENT.name())
.message("Skipped redaction was resized to be redacted")
.details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, response.getAnnotationId()))
.build()));
return responseList;
}

View File

@ -46,6 +46,7 @@ public interface ManualRedactionResource {
String COMMENT_ID_PATH_VARIABLE = "/{" + COMMENT_ID + "}";
String FALSE = "false";
String TRUE = "true";
@ResponseStatus(value = HttpStatus.NO_CONTENT)
@ -59,7 +60,11 @@ public interface ManualRedactionResource {
@ResponseStatus(value = HttpStatus.OK)
@PostMapping(value = MANUAL_REDACTION_REST_PATH + "/comment/add" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE + ANNOTATION_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = MANUAL_REDACTION_REST_PATH
+ "/comment/add"
+ DOSSIER_ID_PATH_PARAM
+ FILE_ID_PATH_VARIABLE
+ ANNOTATION_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Adds a comment to a redaction/redaction request", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
CommentResponse addComment(@PathVariable(DOSSIER_ID) String dossierId,
@ -79,7 +84,10 @@ public interface ManualRedactionResource {
@ResponseStatus(value = HttpStatus.OK)
@PostMapping(value = MANUAL_REDACTION_REST_PATH + "/bulk/redaction/add" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = MANUAL_REDACTION_REST_PATH
+ "/bulk/redaction/add"
+ DOSSIER_ID_PATH_PARAM
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Adds a manual redaction", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
List<ManualAddResponse> addRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
@ -88,7 +96,10 @@ public interface ManualRedactionResource {
@ResponseStatus(value = HttpStatus.OK)
@PostMapping(value = MANUAL_REDACTION_REST_PATH + "/bulk/redaction/remove" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = MANUAL_REDACTION_REST_PATH
+ "/bulk/redaction/remove"
+ DOSSIER_ID_PATH_PARAM
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Removes the redactions list", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
List<ManualAddResponse> removeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
@ -98,7 +109,10 @@ public interface ManualRedactionResource {
@ResponseStatus(value = HttpStatus.OK)
@PostMapping(value = MANUAL_REDACTION_REST_PATH + "/bulk/redaction/force" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = MANUAL_REDACTION_REST_PATH
+ "/bulk/redaction/force"
+ DOSSIER_ID_PATH_PARAM
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Forces the redactions list", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
List<ManualAddResponse> forceRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
@ -107,7 +121,10 @@ public interface ManualRedactionResource {
@ResponseStatus(value = HttpStatus.OK)
@PostMapping(value = MANUAL_REDACTION_REST_PATH + "/bulk/redaction/legalBasisChange" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = MANUAL_REDACTION_REST_PATH
+ "/bulk/redaction/legalBasisChange"
+ DOSSIER_ID_PATH_PARAM
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Changes the legal basis reasons list", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
List<ManualAddResponse> legalBasisChangeBulk(@PathVariable(DOSSIER_ID) String dossierId,
@ -116,7 +133,10 @@ public interface ManualRedactionResource {
@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)
@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 list of redaction log entries", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
List<ManualAddResponse> recategorizeBulk(@PathVariable(DOSSIER_ID) String dossierId,
@ -126,7 +146,10 @@ public interface ManualRedactionResource {
@ResponseStatus(value = HttpStatus.OK)
@PostMapping(value = MANUAL_REDACTION_REST_PATH + "/bulk/redaction/resize" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@PostMapping(value = MANUAL_REDACTION_REST_PATH
+ "/bulk/redaction/resize"
+ DOSSIER_ID_PATH_PARAM
+ FILE_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Resizes the redactions list", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found"), @ApiResponse(responseCode = "403", description = "Forbidden")})
List<ManualAddResponse> resizeRedactionBulk(@PathVariable(DOSSIER_ID) String dossierId,
@ -137,15 +160,24 @@ public interface ManualRedactionResource {
@ResponseStatus(value = HttpStatus.OK)
@GetMapping(value = MANUAL_REDACTION_REST_PATH + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Returns the manual redactions", description = "If the unprocessed flag is true then only the unprocessed manual redactions are returned. If the flag is false" + "all manual redactions are returned. Default value for the flag is false.")
@Operation(summary = "Returns the manual redactions", description = """
If the unprocessed flag is true then only the unprocessed manual redactions are returned. If the flag is false\
all manual redactions are returned. Default value for the flag is false.\
If the includeDictChanges flag is false, only local manual redactions will be returned, otherwise all are returned. Default value for the flag is true.
""")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found")})
ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed);
@RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed,
@RequestParam(value = "includeDictChanges", required = false, defaultValue = TRUE) boolean includeDictChanges);
@ResponseStatus(value = HttpStatus.OK)
@GetMapping(value = MANUAL_REDACTION_REST_PATH + "/comments" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE + ANNOTATION_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
@GetMapping(value = MANUAL_REDACTION_REST_PATH
+ "/comments"
+ DOSSIER_ID_PATH_PARAM
+ FILE_ID_PATH_VARIABLE
+ ANNOTATION_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Returns the comments for a specific annotation in a specific file", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Dossier or file not found")})
AnnotationComments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @PathVariable(ANNOTATION_ID) String annotationId);

View File

@ -5,6 +5,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.
import com.iqser.red.service.persistence.management.v1.processor.entity.migration.SaasMigrationStatusEntity;
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.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.DossierService;
import com.iqser.red.service.persistence.management.v1.processor.service.IndexingService;
import com.iqser.red.service.persistence.management.v1.processor.service.job.AutomaticAnalysisJob;
@ -163,7 +164,7 @@ public class SaasMigrationService implements TenantSyncService {
.dossierTemplateId(dossierTemplateId)
.dossierId(dossierId)
.fileId(fileId)
.manualRedactions(manualRedactionProviderService.getManualRedactions(fileId))
.manualRedactions(manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.allWithoutDeleted()))
.build());
log.info("Layout Parsing finished for saas migration for tenant {} dossier {} and file {}", TenantContext.getTenantId(), dossierId, fileId);
} catch (Exception e) {

View File

@ -0,0 +1,101 @@
package com.iqser.red.service.persistence.management.v1.processor.migration.migrations;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity;
import com.iqser.red.service.persistence.management.v1.processor.migration.Migration;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ManualChange;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ManualRedactionType;
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.BaseAnnotation;
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.ManualRecategorization;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualResizeRedaction;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Setter
@Service
public class ManualRedactionTypeRenameMigration15 extends Migration {
@Autowired
private FileStatusPersistenceService fileStatusPersistenceService;
@Autowired
private FileManagementStorageService fileManagementStorageService;
@Autowired
private ManualRedactionService manualRedactionService;
public ManualRedactionTypeRenameMigration15() {
super(NAME, VERSION);
}
private static final String NAME = "Migrate ManualRedactionType names in EntityLog";
private static final long VERSION = 15;
@Override
/*
* Migrates the ManualRedactionType ADD_LOCALLY -> ADD, FORCE_REDACT -> FORCE, FORCE_HINT -> FORCE, REMOVE_LOCALLY -> REMOVE.
*/
protected void migrate() {
log.info("Migrating ManualRedactionType names");
Set<Class<? extends BaseAnnotation>> excludedClasses = Set.of(ManualResizeRedaction.class, ManualRecategorization.class, ManualLegalBasisChange.class);
ManualChangesQueryOptions options = ManualChangesQueryOptions.builder().includeDictChanges(false).excludedClasses(excludedClasses).build();
var files = fileStatusPersistenceService.getAllFiles();
for (FileEntity file : files) {
ManualRedactions manualChanges = manualRedactionService.getManualRedactions(file.getId(), options);
if (manualChanges.isEmpty()) {
continue;
}
if (!fileManagementStorageService.objectExists(file.getDossierId(), file.getId(), FileType.ENTITY_LOG)) {
continue;
}
log.info("Migrating ManualRedactionType names for fileId {}", file.getId());
EntityLog entityLog = fileManagementStorageService.getEntityLog(file.getDossierId(), file.getId());
for (EntityLogEntry entityLogEntry : entityLog.getEntityLogEntry()) {
for (ManualChange manualChange : entityLogEntry.getManualChanges()) {
if (manualChange.getManualRedactionType().equals(ManualRedactionType.ADD_LOCALLY)) {
manualChange.setManualRedactionType(ManualRedactionType.ADD);
}
if (manualChange.getManualRedactionType().equals(ManualRedactionType.FORCE_REDACT)) {
manualChange.setManualRedactionType(ManualRedactionType.FORCE);
}
if (manualChange.getManualRedactionType().equals(ManualRedactionType.FORCE_HINT)) {
manualChange.setManualRedactionType(ManualRedactionType.FORCE);
}
if (manualChange.getManualRedactionType().equals(ManualRedactionType.REMOVE_LOCALLY)) {
manualChange.setManualRedactionType(ManualRedactionType.REMOVE);
}
}
}
fileManagementStorageService.storeJSONObject(file.getDossierId(), file.getId(), FileType.ENTITY_LOG, entityLog);
}
}
}

View File

@ -0,0 +1,51 @@
package com.iqser.red.service.persistence.management.v1.processor.model;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.BaseAnnotation;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRedactionEntry;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
@SuppressWarnings("checkstyle:all") // explicit initialization of false. IMO it improves readability here.
public class ManualChangesQueryOptions {
@Builder.Default
private boolean includeOnlyUnprocessed = false;
@Builder.Default
private boolean includeDictChanges = true;
@Builder.Default
private boolean includeDeletions = false;
@Builder.Default
private Set<Class<? extends BaseAnnotation>> excludedClasses = Collections.emptySet();
public static ManualChangesQueryOptions allWithoutDeleted() {
return ManualChangesQueryOptions.builder().includeDeletions(false).includeDictChanges(true).includeOnlyUnprocessed(false).build();
}
public static ManualChangesQueryOptions all() {
return ManualChangesQueryOptions.builder().includeDeletions(true).includeDictChanges(true).includeOnlyUnprocessed(false).build();
}
public static ManualChangesQueryOptions unprocessedOnly() {
return ManualChangesQueryOptions.builder().includeDeletions(false).includeDictChanges(true).includeOnlyUnprocessed(true).build();
}
public static ManualChangesQueryOptions localChangesOnly() {
return ManualChangesQueryOptions.builder().includeDeletions(false).includeDictChanges(false).includeOnlyUnprocessed(false).build();
}
}

View File

@ -157,11 +157,10 @@ public class AnalysisFlagsCalculationService {
return !entryType.equals(EntryType.HINT) && //
!entryType.equals(EntryType.RECOMMENDATION) && //
StringUtils.isNotEmpty(entry.getReason()) && //
(manualChange.getManualRedactionType().equals(ManualRedactionType.ADD_LOCALLY) || //
(manualChange.getManualRedactionType().equals(ManualRedactionType.ADD) || //
manualChange.getManualRedactionType().equals(ManualRedactionType.RECATEGORIZE) || //
manualChange.getManualRedactionType().equals(ManualRedactionType.REMOVE_LOCALLY) || //
manualChange.getManualRedactionType().equals(ManualRedactionType.FORCE_REDACT) || //
manualChange.getManualRedactionType().equals(ManualRedactionType.FORCE_HINT) || //
manualChange.getManualRedactionType().equals(ManualRedactionType.REMOVE) || //
manualChange.getManualRedactionType().equals(ManualRedactionType.FORCE) || //
manualChange.getManualRedactionType().equals(ManualRedactionType.LEGAL_BASIS_CHANGE) || //
manualChange.getManualRedactionType().equals(ManualRedactionType.RESIZE)) && //
manualChange.getProcessedDate() != null && //

View File

@ -4,7 +4,7 @@ import static com.iqser.red.service.persistence.management.v1.processor.utils.Ty
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@ -13,7 +13,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
@ -24,6 +23,7 @@ import com.iqser.red.service.persistence.management.v1.processor.configuration.M
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.TypeEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.PendingDictionaryEntryFactory;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.AnalyzeRequest;
@ -51,35 +51,48 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType;
import io.micrometer.observation.annotation.Observed;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;
@Service
@Slf4j
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
public class EntityLogMergeService {
private final DictionaryPersistenceService dictionaryPersistenceService;
private final RabbitTemplate rabbitTemplate;
private final FileStatusService fileStatusService;
private final FileStatusPersistenceService fileStatusPersistenceService;
DictionaryPersistenceService dictionaryPersistenceService;
RabbitTemplate rabbitTemplate;
FileStatusService fileStatusService;
FileStatusPersistenceService fileStatusPersistenceService;
PendingDictionaryEntryFactory pendingDictionaryEntryFactory;
@Observed(name = "EntityLogMergeService", contextualName = "merge-entity-log")
public EntityLog mergeEntityLog(ManualRedactions manualRedactions, EntityLog entityLog, DossierEntity dossier) {
log.debug("Merging EntityLog");
List<BaseAnnotation> allManualChanges = allManualChanges(manualRedactions);
List<String> manualChangesIds = allManualChanges.stream().map(BaseAnnotation::getAnnotationId).toList();
List<BaseAnnotation> allManualChanges = manualRedactions.buildAll();
List<String> manualChangesIds = allManualChanges.stream()
.map(BaseAnnotation::getAnnotationId)
.toList();
List<EntityLogEntry> matchingEntities = entityLog.getEntityLogEntry()
.stream()
.filter(entityLogEntry -> manualChangesIds.contains(entityLogEntry.getId()))
.collect(Collectors.toList());
final int analysisNumber = entityLog.getAnalysisNumber();
// Sort manual changes by date, so we process them in order of when they were requested
allManualChanges = allManualChanges.stream().sorted(Comparator.comparing(BaseAnnotation::getRequestDate)).toList();
allManualChanges.forEach(manualChange -> {
List<BaseAnnotation> allLocalManualChanges = allManualChanges.stream()
.filter(BaseAnnotation::isLocal)
.sorted(Comparator.comparing(BaseAnnotation::getRequestDate))
.toList();
allLocalManualChanges.forEach(manualChange -> {
// this is ugly and should be replaced with switch pattern matching https://openjdk.org/jeps/406 -> requires Java 17 (preview) or higher
if (manualChange instanceof ManualRedactionEntry manualRedactionEntry) {
var entityLogEntry = mergeManualRedactionEntries(manualRedactionEntry, entityLog, dossier);
@ -97,11 +110,45 @@ public class EntityLogMergeService {
}
});
// Sort manual changes by date, so we process them in order of when they were requested
List<BaseAnnotation> allDictionaryManualChanges = allManualChanges.stream()
.filter(baseAnnotation -> !baseAnnotation.isLocal())
.sorted(Comparator.comparing(BaseAnnotation::getRequestDate))
.toList();
List<EntityLogEntry> pendingEntries = allDictionaryManualChanges.stream()
.map(manualChange -> {
if (manualChange instanceof ManualRedactionEntry manualRedactionEntry) {
return pendingDictionaryEntryFactory.buildAddToDictionaryEntry(manualRedactionEntry);
} else if (manualChange instanceof IdRemoval idRemoval) {
return pendingDictionaryEntryFactory.buildRemoveFromDictionary(idRemoval, findMatchingEntry(idRemoval.getAnnotationId(), matchingEntities));
} else if (manualChange instanceof ManualResizeRedaction manualResizeRedaction) {
return pendingDictionaryEntryFactory.buildResizeWithDictionary(manualResizeRedaction, findMatchingEntry(manualChange.getAnnotationId(), matchingEntities));
} else if (manualChange instanceof ManualRecategorization manualRecategorization) {
return pendingDictionaryEntryFactory.buildRecategorizeWithDictionary(manualRecategorization,
findMatchingEntry(manualChange.getAnnotationId(), matchingEntities));
} else {
throw new IllegalArgumentException(String.format("Manual change of type %s has no defined dictionary action!", manualChange.getClass()));
}
})
.toList();
entityLog.getEntityLogEntry().addAll(pendingEntries);
log.debug("EntityLog merged successfully.");
return entityLog;
}
private EntityLogEntry findMatchingEntry(String annotationId, List<EntityLogEntry> matchingEntities) {
return matchingEntities.stream()
.filter(entityLogEntry -> entityLogEntry.getId().equals(annotationId))
.findAny()
.orElseThrow(() -> new NotFoundException("No matching EntityLogEntry found for id " + annotationId));
}
private Optional<EntityLogEntry> mergeManualRedactionEntries(ManualRedactionEntry manualRedactionEntry, EntityLog entityLog, DossierEntity dossier) {
if (manualRedactionEntry.getPositions() == null || manualRedactionEntry.getPositions().isEmpty()) {
@ -111,7 +158,10 @@ public class EntityLogMergeService {
if (isFalsePositive(manualRedactionEntry)) {
var matchingEntities = entityLog.getEntityLogEntry()
.stream()
.filter(entityLogEntry -> equalPosition(manualRedactionEntry.getPositions().get(0), entityLogEntry.getPositions().get(0)))
.filter(entityLogEntry -> equalPosition(manualRedactionEntry.getPositions()
.get(0),
entityLogEntry.getPositions()
.get(0)))
.toList();
matchingEntities.forEach(matchingEntity -> mergeFalsePositive(entityLog, matchingEntity));
return Optional.empty();
@ -119,12 +169,12 @@ public class EntityLogMergeService {
List<ManualChange> manualChanges = new ArrayList<>();
manualChanges.add(ManualChange.builder()
.manualRedactionType(calculateManualRedactionType(manualRedactionEntry))
.requestedDate(manualRedactionEntry.getRequestDate())
.processedDate(null)
.userId(manualRedactionEntry.getUser())
.propertyChanges(Map.of("value", manualRedactionEntry.getValue()))
.build());
.manualRedactionType(ManualRedactionType.ADD)
.requestedDate(manualRedactionEntry.getRequestDate())
.processedDate(null)
.userId(manualRedactionEntry.getUser())
.propertyChanges(Map.of("value", manualRedactionEntry.getValue()))
.build());
List<Change> changes = new ArrayList<>();
changes.add(Change.builder().analysisNumber(entityLog.getAnalysisNumber()).dateTime(manualRedactionEntry.getRequestDate()).type(ChangeType.ADDED).build());
@ -154,6 +204,10 @@ public class EntityLogMergeService {
.engines(Set.of(Engine.MANUAL))
.reference(new HashSet<>())
.importedRedactionIntersections(new HashSet<>())
.containingNodeId(Collections.emptyList())
.closestHeadline("")
.startOffset(-1)
.endOffset(-1)
.build();
entityLog.getEntityLogEntry().add(entityLogEntry);
@ -182,25 +236,30 @@ public class EntityLogMergeService {
private void mergeIdsToRemove(IdRemoval idRemoval, List<EntityLogEntry> entityLogEntries, int analysisNumber) {
var entity = entityLogEntries.stream().filter(entityLogEntry -> entityLogEntry.getId().equals(idRemoval.getAnnotationId())).findAny();
var entity = entityLogEntries.stream()
.filter(entityLogEntry -> entityLogEntry.getId().equals(idRemoval.getAnnotationId()))
.findAny();
entity.ifPresent(entityLogEntry -> {
entityLogEntry.setState(EntryState.IGNORED);
entityLogEntry.getEngines().add(Engine.MANUAL);
addChanges(entityLogEntry.getChanges(), ChangeType.REMOVED, analysisNumber, idRemoval.getRequestDate());
entityLogEntry.getManualChanges()
.add(ManualChange.builder()
.manualRedactionType(idRemoval.isRemoveFromDictionary() ? ManualRedactionType.REMOVE_FROM_DICTIONARY : ManualRedactionType.REMOVE_LOCALLY)
.requestedDate(idRemoval.getRequestDate())
.processedDate(null)
.userId(idRemoval.getUser())
.build());
.manualRedactionType(ManualRedactionType.REMOVE)
.requestedDate(idRemoval.getRequestDate())
.processedDate(null)
.userId(idRemoval.getUser())
.propertyChanges(Collections.emptyMap())
.build());
});
}
private void mergeResizeRedactions(ManualResizeRedaction manualResizeRedaction, List<EntityLogEntry> entityLogEntries, int analysisNumber) {
var entity = entityLogEntries.stream().filter(entityLogEntry -> entityLogEntry.getId().equals(manualResizeRedaction.getAnnotationId())).findAny();
var entity = entityLogEntries.stream()
.filter(entityLogEntry -> entityLogEntry.getId().equals(manualResizeRedaction.getAnnotationId()))
.findAny();
entity.ifPresent(entityLogEntry -> {
entityLogEntry.setTextAfter(manualResizeRedaction.getTextAfter());
entityLogEntry.setTextBefore(manualResizeRedaction.getTextBefore());
@ -209,7 +268,7 @@ public class EntityLogMergeService {
entityLogEntry.getEngines().add(Engine.MANUAL);
addChanges(entityLogEntry.getChanges(), ChangeType.CHANGED, analysisNumber, manualResizeRedaction.getRequestDate());
ManualChange.ManualChangeBuilder manualChange = ManualChange.builder()
.manualRedactionType(manualResizeRedaction.getUpdateDictionary() ? ManualRedactionType.RESIZE_IN_DICTIONARY : ManualRedactionType.RESIZE)
.manualRedactionType(ManualRedactionType.RESIZE)
.requestedDate(manualResizeRedaction.getRequestDate())
.processedDate(null)
.userId(manualResizeRedaction.getUser());
@ -223,7 +282,9 @@ public class EntityLogMergeService {
private void mergeLegalBasisChanges(ManualLegalBasisChange manualLegalBasisChange, List<EntityLogEntry> entityLogEntries, int analysisNumber) {
var entity = entityLogEntries.stream().filter(entityLogEntry -> entityLogEntry.getId().equals(manualLegalBasisChange.getAnnotationId())).findAny();
var entity = entityLogEntries.stream()
.filter(entityLogEntry -> entityLogEntry.getId().equals(manualLegalBasisChange.getAnnotationId()))
.findAny();
entity.ifPresent(entityLogEntry -> {
entityLogEntry.setLegalBasis(manualLegalBasisChange.getLegalBasis());
entityLogEntry.setSection(manualLegalBasisChange.getSection());
@ -233,12 +294,12 @@ public class EntityLogMergeService {
Map<String, String> propertyChanges = getPropertyChanges(manualLegalBasisChange);
entityLogEntry.getManualChanges()
.add(ManualChange.builder()
.manualRedactionType(ManualRedactionType.LEGAL_BASIS_CHANGE)
.requestedDate(manualLegalBasisChange.getRequestDate())
.processedDate(null)
.propertyChanges(propertyChanges)
.userId(manualLegalBasisChange.getUser())
.build());
.manualRedactionType(ManualRedactionType.LEGAL_BASIS_CHANGE)
.requestedDate(manualLegalBasisChange.getRequestDate())
.processedDate(null)
.propertyChanges(propertyChanges)
.userId(manualLegalBasisChange.getUser())
.build());
});
}
@ -263,7 +324,9 @@ public class EntityLogMergeService {
private void mergeRecategorizations(ManualRecategorization recategorization, List<EntityLogEntry> entityLogEntries, DossierEntity dossier, int analysisNumber) {
boolean isHint = isHint(recategorization.getType(), dossier);
var entity = entityLogEntries.stream().filter(entityLogEntry -> entityLogEntry.getId().equals(recategorization.getAnnotationId())).findAny();
var entity = entityLogEntries.stream()
.filter(entityLogEntry -> entityLogEntry.getId().equals(recategorization.getAnnotationId()))
.findAny();
entity.ifPresent(entityLogEntry -> {
entityLogEntry.setType(recategorization.getType());
entityLogEntry.setEntryType(getEntryType(isHint, recategorization.getType()));
@ -272,26 +335,28 @@ public class EntityLogMergeService {
addChanges(entityLogEntry.getChanges(), ChangeType.CHANGED, analysisNumber, recategorization.getRequestDate());
entityLogEntry.getManualChanges()
.add(ManualChange.builder()
.manualRedactionType(ManualRedactionType.RECATEGORIZE)
.requestedDate(recategorization.getRequestDate())
.processedDate(recategorization.getProcessedDate())
.userId(recategorization.getUser())
.propertyChanges(Map.of("type", recategorization.getType()))
.build());
.manualRedactionType(ManualRedactionType.RECATEGORIZE)
.requestedDate(recategorization.getRequestDate())
.processedDate(recategorization.getProcessedDate())
.userId(recategorization.getUser())
.propertyChanges(Map.of("type", recategorization.getType()))
.build());
});
}
private void mergeForceRedactions(ManualForceRedaction forceRedaction, List<EntityLogEntry> entityLogEntries, int analysisNumber) {
var entity = entityLogEntries.stream().filter(entityLogEntry -> entityLogEntry.getId().equals(forceRedaction.getAnnotationId())).findAny();
var entity = entityLogEntries.stream()
.filter(entityLogEntry -> entityLogEntry.getId().equals(forceRedaction.getAnnotationId()))
.findAny();
entity.ifPresent(entityLogEntry -> {
entityLogEntry.setLegalBasis(forceRedaction.getLegalBasis());
entityLogEntry.setState(entityLogEntry.getEntryType().equals(EntryType.HINT) ? EntryState.SKIPPED : EntryState.APPLIED);
entityLogEntry.getEngines().add(Engine.MANUAL);
addChanges(entityLogEntry.getChanges(), ChangeType.CHANGED, analysisNumber, forceRedaction.getRequestDate());
var forceRedactManualChange = ManualChange.builder()
.manualRedactionType(entityLogEntry.getEntryType().equals(EntryType.HINT) ? ManualRedactionType.FORCE_HINT : ManualRedactionType.FORCE_REDACT)
.manualRedactionType(ManualRedactionType.FORCE)
.requestedDate(forceRedaction.getRequestDate())
.processedDate(forceRedaction.getProcessedDate())
.userId(forceRedaction.getUser());
@ -313,15 +378,6 @@ public class EntityLogMergeService {
}
private ManualRedactionType calculateManualRedactionType(ManualRedactionEntry manualRedactionEntry) {
if (manualRedactionEntry.isAddToDictionary() || manualRedactionEntry.isAddToDossierDictionary()) {
return ManualRedactionType.ADD_TO_DICTIONARY;
}
return ManualRedactionType.ADD_LOCALLY;
}
private void addChanges(List<Change> changes, ChangeType changeType, int analysisNumber, OffsetDateTime offsetDateTime) {
if (!changes.isEmpty()) {
@ -338,7 +394,10 @@ public class EntityLogMergeService {
TypeEntity typeEntity = dictionaryPersistenceService.getType(typeId);
if (typeEntity == null) {
var optionalType = dictionaryPersistenceService.getAllTypes(false).stream().filter(typeEntity1 -> typeEntity1.getType().equals(type)).findFirst();
var optionalType = dictionaryPersistenceService.getAllTypes(false)
.stream()
.filter(typeEntity1 -> typeEntity1.getType().equals(type))
.findFirst();
if (optionalType.isPresent()) {
typeEntity = optionalType.get();
} else {
@ -352,7 +411,10 @@ public class EntityLogMergeService {
private boolean equalPosition(Rectangle position1, Position position2) {
return position1.getTopLeftX() == position2.x() && position1.getTopLeftY() == position2.y() && position1.getWidth() == position2.w() && position1.getHeight() == position2.h();
return position1.getTopLeftX() == position2.x()
&& position1.getTopLeftY() == position2.y()
&& position1.getWidth() == position2.w()
&& position1.getHeight() == position2.h();
}
@ -364,17 +426,6 @@ public class EntityLogMergeService {
}
private List<BaseAnnotation> allManualChanges(ManualRedactions manualRedactions) {
return Stream.of(manualRedactions.getEntriesToAdd(),
manualRedactions.getForceRedactions(),
manualRedactions.getResizeRedactions(),
manualRedactions.getRecategorizations(),
manualRedactions.getIdsToRemove(),
manualRedactions.getLegalBasisChanges()).flatMap(Collection::stream).map(baseAnnotation -> (BaseAnnotation) baseAnnotation).toList();
}
public void sendToAnalyseQueue(String fileId, DossierEntity dossier, FileModel fileModel, ManualRedactions manualRedactions) {
var fileEntity = fileStatusPersistenceService.getStatus(fileId);

View File

@ -8,9 +8,9 @@ import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry;
@ -64,18 +64,23 @@ public class EntityLogService {
if (includeUnprocessed) {
DossierEntity dossier = dossierService.getDossierById(dossierId);
ManualRedactions manualRedactions = manualRedactionProviderService.getManualRedactions(fileId, true);
ManualRedactions manualRedactions = manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.unprocessedOnly());
entityLogMergeService.mergeEntityLog(manualRedactions, entityLog, dossier);
}
if (fileStatus.getExcludedPages() != null && !fileStatus.getExcludedPages().isEmpty()) {
entityLog.getEntityLogEntry()
.removeIf(entry -> entry.getPositions().stream().anyMatch(position -> fileStatus.getExcludedPages().contains(position.getPageNumber())) //
&& entry.getManualChanges().stream().noneMatch(m -> m.getManualRedactionType().equals(ManualRedactionType.ADD_LOCALLY)));
.removeIf(entry -> entry.getPositions()
.stream()
.anyMatch(position -> fileStatus.getExcludedPages().contains(position.getPageNumber())) //
&& entry.getManualChanges()
.stream()
.noneMatch(m -> m.getManualRedactionType().equals(ManualRedactionType.ADD)));
}
Map<String, Integer> commentCountPerAnnotationId = commentService.getCommentCounts(fileId);
entityLog.getEntityLogEntry().forEach(entityLogEntry -> entityLogEntry.setNumberOfComments(commentCountPerAnnotationId.getOrDefault(entityLogEntry.getId(), 0)));
entityLog.getEntityLogEntry()
.forEach(entityLogEntry -> entityLogEntry.setNumberOfComments(commentCountPerAnnotationId.getOrDefault(entityLogEntry.getId(), 0)));
return entityLog;
}
@ -102,7 +107,7 @@ public class EntityLogService {
}
for (var manualChange : redactionLogEntry.getManualChanges()) {
if (manualChange.getProcessedDate() != null && manualChange.getProcessedDate().isAfter(filteredEntityLogRequest.getSpecifiedDate()) || //
manualChange.getRequestedDate() != null && manualChange.getRequestedDate().isAfter(filteredEntityLogRequest.getSpecifiedDate())) {
manualChange.getRequestedDate() != null && manualChange.getRequestedDate().isAfter(filteredEntityLogRequest.getSpecifiedDate())) {
isAfterSpecifiedDate = true;
break;
}

View File

@ -14,6 +14,7 @@ import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException;
import com.iqser.red.service.persistence.management.v1.processor.exception.DossierNotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ViewedPagesPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService;
@ -114,42 +115,44 @@ public class FileService {
public void softDeleteFile(String dossierId, String fileId, OffsetDateTime softDeletedTime) {
forceRedactionPersistenceService.findForceRedactions(fileId, false)
ManualChangesQueryOptions options = ManualChangesQueryOptions.allWithoutDeleted();
forceRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
forceRedactionPersistenceService.softDelete(fileId, annotation.getId().getAnnotationId(), softDeletedTime);
commentPersistenceService.findCommentsByAnnotationId(fileId, annotation.getId().getAnnotationId(), false)
.forEach(comment -> commentPersistenceService.softDelete(comment.getId(), softDeletedTime));
});
removeRedactionPersistenceService.findRemoveRedactions(fileId, false)
removeRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
removeRedactionPersistenceService.softDelete(fileId, annotation.getId().getAnnotationId(), softDeletedTime);
commentPersistenceService.findCommentsByAnnotationId(fileId, annotation.getId().getAnnotationId(), false)
.forEach(comment -> commentPersistenceService.softDelete(comment.getId(), softDeletedTime));
});
addRedactionPersistenceService.findAddRedactions(fileId, false)
addRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
addRedactionPersistenceService.softDelete(fileId, annotation.getId().getAnnotationId(), softDeletedTime);
commentPersistenceService.findCommentsByAnnotationId(fileId, annotation.getId().getAnnotationId(), false)
.forEach(comment -> commentPersistenceService.softDelete(comment.getId(), softDeletedTime));
});
recategorizationPersistenceService.findRecategorizations(fileId, false)
recategorizationPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(recatigorization -> {
recategorizationPersistenceService.softDelete(fileId, recatigorization.getId().getAnnotationId(), softDeletedTime);
commentPersistenceService.findCommentsByAnnotationId(fileId, recatigorization.getId().getAnnotationId(), false)
.forEach(comment -> commentPersistenceService.softDelete(comment.getId(), softDeletedTime));
});
resizeRedactionPersistenceService.findResizeRedactions(fileId, false)
resizeRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
resizeRedactionPersistenceService.softDelete(fileId, annotation.getId().getAnnotationId(), softDeletedTime);
commentPersistenceService.findCommentsByAnnotationId(fileId, annotation.getId().getAnnotationId(), false)
.forEach(comment -> commentPersistenceService.softDelete(comment.getId(), softDeletedTime));
});
legalBasisChangePersistenceService.findLegalBasisChanges(fileId, false)
legalBasisChangePersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(legalBasisChange -> {
legalBasisChangePersistenceService.softDelete(fileId, legalBasisChange.getId().getAnnotationId(), softDeletedTime);
commentPersistenceService.findCommentsByAnnotationId(fileId, legalBasisChange.getId().getAnnotationId(), false)
@ -187,35 +190,37 @@ public class FileService {
}
});
forceRedactionPersistenceService.findForceRedactions(fileId, true)
ManualChangesQueryOptions options = ManualChangesQueryOptions.all();
forceRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
forceRedactionPersistenceService.hardDelete(fileId, annotation.getId().getAnnotationId());
commentPersistenceService.findCommentsByAnnotationId(fileId, annotation.getId().getAnnotationId(), true)
.forEach(comment -> commentPersistenceService.hardDelete(comment.getId()));
});
removeRedactionPersistenceService.findRemoveRedactions(fileId, true)
removeRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
removeRedactionPersistenceService.hardDelete(fileId, annotation.getId().getAnnotationId());
commentPersistenceService.findCommentsByAnnotationId(fileId, annotation.getId().getAnnotationId(), true)
.forEach(comment -> commentPersistenceService.hardDelete(comment.getId()));
});
addRedactionPersistenceService.findAddRedactions(fileId, true)
addRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
addRedactionPersistenceService.hardDelete(fileId, annotation.getId().getAnnotationId());
commentPersistenceService.findCommentsByAnnotationId(fileId, annotation.getId().getAnnotationId(), true)
.forEach(comment -> commentPersistenceService.hardDelete(comment.getId()));
});
recategorizationPersistenceService.findRecategorizations(fileId, true)
recategorizationPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(recatigorization -> {
recategorizationPersistenceService.hardDelete(fileId, recatigorization.getId().getAnnotationId());
commentPersistenceService.findCommentsByAnnotationId(fileId, recatigorization.getId().getAnnotationId(), true)
.forEach(comment -> commentPersistenceService.hardDelete(comment.getId()));
});
resizeRedactionPersistenceService.findResizeRedactions(fileId, true)
resizeRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
resizeRedactionPersistenceService.hardDelete(fileId, annotation.getId().getAnnotationId());
commentPersistenceService.findCommentsByAnnotationId(fileId, annotation.getId().getAnnotationId(), true)
@ -246,7 +251,8 @@ public class FileService {
public void undeleteFile(String dossierTemplateId, String dossierId, String fileId, OffsetDateTime softDeletedTime) {
forceRedactionPersistenceService.findForceRedactions(fileId, true)
ManualChangesQueryOptions options = ManualChangesQueryOptions.all();
forceRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
if (annotation.getSoftDeletedTime().equals(softDeletedTime) || annotation.getSoftDeletedTime().isAfter(softDeletedTime)) {
forceRedactionPersistenceService.undelete(fileId, annotation.getId().getAnnotationId());
@ -259,7 +265,7 @@ public class FileService {
}
});
removeRedactionPersistenceService.findRemoveRedactions(fileId, true)
removeRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
if (annotation.getSoftDeletedTime().equals(softDeletedTime) || annotation.getSoftDeletedTime().isAfter(softDeletedTime)) {
removeRedactionPersistenceService.undelete(fileId, annotation.getId().getAnnotationId());
@ -272,7 +278,7 @@ public class FileService {
}
});
addRedactionPersistenceService.findAddRedactions(fileId, true)
addRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
if (annotation != null && annotation.getSoftDeletedTime() != null && (annotation.getSoftDeletedTime().equals(softDeletedTime) || annotation.getSoftDeletedTime()
.isAfter(softDeletedTime))) {
@ -286,7 +292,7 @@ public class FileService {
}
});
recategorizationPersistenceService.findRecategorizations(fileId, true)
recategorizationPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(recatigorization -> {
if (recatigorization.getSoftDeletedTime().equals(softDeletedTime) || recatigorization.getSoftDeletedTime().isAfter(softDeletedTime)) {
recategorizationPersistenceService.undelete(fileId, recatigorization.getId().getAnnotationId());
@ -299,7 +305,7 @@ public class FileService {
}
});
resizeRedactionPersistenceService.findResizeRedactions(fileId, true)
resizeRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
if (annotation.getSoftDeletedTime().equals(softDeletedTime) || annotation.getSoftDeletedTime().isAfter(softDeletedTime)) {
resizeRedactionPersistenceService.undelete(fileId, annotation.getId().getAnnotationId());
@ -312,7 +318,7 @@ public class FileService {
}
});
legalBasisChangePersistenceService.findLegalBasisChanges(fileId, true)
legalBasisChangePersistenceService.findEntriesByFileIdAndOptions(fileId, options)
.forEach(annotation -> {
if (annotation.getSoftDeletedTime().equals(softDeletedTime) || annotation.getSoftDeletedTime().isAfter(softDeletedTime)) {
legalBasisChangePersistenceService.undelete(fileId, annotation.getId().getAnnotationId());

View File

@ -22,6 +22,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.
import com.iqser.red.service.persistence.management.v1.processor.exception.InternalServerErrorException;
import com.iqser.red.service.persistence.management.v1.processor.model.CvAnalysisServiceRequest;
import com.iqser.red.service.persistence.management.v1.processor.model.FileIdentifier;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.model.NerServiceRequest;
import com.iqser.red.service.persistence.management.v1.processor.model.OCRStatusUpdateResponse;
import com.iqser.red.service.persistence.management.v1.processor.model.image.ImageServiceRequest;
@ -226,7 +227,7 @@ public class FileStatusService {
.analysisNumber(fileModel.getNumberOfAnalyses() + 1)
.sectionsToReanalyse(sectionsToReanalyse)
.fileId(fileId)
.manualRedactions(manualRedactionProviderService.getManualRedactions(fileId))
.manualRedactions(manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.allWithoutDeleted()))
.dossierTemplateId(dossier.getDossierTemplateId())
.lastProcessed(fileModel.getLastProcessed())
.fileAttributes(convertAttributes(fileEntity.getFileAttributes(), dossier.getDossierTemplateId()))
@ -695,27 +696,28 @@ public class FileStatusService {
comments.forEach((key, value) -> value.forEach(comment -> commentPersistenceService.softDelete(comment.getId(), now)));
// wipe force redactions
var forceRedactions = forceRedactionPersistenceService.findForceRedactions(fileId, false);
ManualChangesQueryOptions options = ManualChangesQueryOptions.allWithoutDeleted();
var forceRedactions = forceRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options);
forceRedactions.forEach(f -> forceRedactionPersistenceService.softDelete(fileId, f.getId().getAnnotationId(), now));
// wipe add manual redactions
var addRedactions = addRedactionPersistenceService.findAddRedactions(fileId, false);
var addRedactions = addRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options);
addRedactions.forEach(f -> addRedactionPersistenceService.softDelete(fileId, f.getId().getAnnotationId(), now));
// wipe removeRedactions
var removeRedactions = removeRedactionPersistenceService.findRemoveRedactions(fileId, false);
var removeRedactions = removeRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options);
removeRedactions.forEach(f -> removeRedactionPersistenceService.softDelete(fileId, f.getId().getAnnotationId(), now));
// wipe image recat
var imageRecategorizations = recategorizationPersistenceService.findRecategorizations(fileId, false);
var imageRecategorizations = recategorizationPersistenceService.findEntriesByFileIdAndOptions(fileId, options);
imageRecategorizations.forEach(f -> recategorizationPersistenceService.softDelete(fileId, f.getId().getAnnotationId(), now));// wipe image recat
// wipe resize redactions
var resizeRedactions = resizeRedactionPersistenceService.findResizeRedactions(fileId, false);
var resizeRedactions = resizeRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options);
resizeRedactions.forEach(f -> resizeRedactionPersistenceService.softDelete(fileId, f.getId().getAnnotationId(), now));
// wipe legal basis changes
var legalBasisChanges = legalBasisChangePersistenceService.findLegalBasisChanges(fileId, false);
var legalBasisChanges = legalBasisChangePersistenceService.findEntriesByFileIdAndOptions(fileId, options);
legalBasisChanges.forEach(f -> legalBasisChangePersistenceService.softDelete(fileId, f.getId().getAnnotationId(), now));
fileStatusPersistenceService.updateHasComments(fileId, false);

View File

@ -2,6 +2,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service.manual
import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter.convert;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -13,6 +14,7 @@ import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.CommentService;
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;
@ -49,13 +51,7 @@ public class ManualRedactionProviderService {
@Transactional
public ManualRedactions getManualRedactions(String fileId) {
return getManualRedactions(fileId, false);
}
public ManualRedactions getManualRedactions(String fileId, boolean unprocessed) {
public ManualRedactions getManualRedactions(String fileId, ManualChangesQueryOptions options) {
Set<ManualRedactionEntry> entriesToAdd;
Set<IdRemoval> removals;
@ -64,37 +60,50 @@ public class ManualRedactionProviderService {
Set<ManualLegalBasisChange> legalBasisChanges;
Set<ManualResizeRedaction> resizeRedactions;
if (unprocessed) {
entriesToAdd = convertEntriesToAdd(addRedactionPersistenceService.findUnprocessedRedactions(fileId));
removals = convert(removeRedactionPersistenceService.findUnprocessedRemoveRedactions(fileId), IdRemoval.class);
forceRedactions = convert(forceRedactionPersistenceService.findUnprocessedForceRedactions(fileId), ManualForceRedaction.class);
recategorizations = new HashSet<>(convert(recategorizationPersistenceService.findUnprocessedRecategorizations(fileId),
ManualRecategorization.class,
new ManualImageRecategorizationMapper()));
legalBasisChanges = convert(legalBasisChangePersistenceService.findUnprocessedLegalBasisChanges(fileId), ManualLegalBasisChange.class);
resizeRedactions = new HashSet<>(convert(resizeRedactionPersistenceService.findUnprocessedResizeRedactions(fileId),
ManualResizeRedaction.class,
new ManualResizeRedactionMapper()));
if (!options.getExcludedClasses().contains(ManualRedactionEntry.class)) {
entriesToAdd = new HashSet<>(convert(addRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options),
ManualRedactionEntry.class,
new ManualRedactionMapper()));
} else {
entriesToAdd = convertEntriesToAdd(addRedactionPersistenceService.findAddRedactions(fileId, false));
removals = convert(removeRedactionPersistenceService.findRemoveRedactions(fileId, false), IdRemoval.class);
forceRedactions = convert(forceRedactionPersistenceService.findForceRedactions(fileId, false), ManualForceRedaction.class);
recategorizations = new HashSet<>(convert(recategorizationPersistenceService.findRecategorizations(fileId, false),
ManualRecategorization.class,
new ManualImageRecategorizationMapper()));
legalBasisChanges = convert(legalBasisChangePersistenceService.findLegalBasisChanges(fileId, false), ManualLegalBasisChange.class);
resizeRedactions = new HashSet<>(convert(resizeRedactionPersistenceService.findResizeRedactions(fileId, false),
ManualResizeRedaction.class,
new ManualResizeRedactionMapper()));
entriesToAdd = Collections.emptySet();
}
if (!options.getExcludedClasses().contains(ManualRecategorization.class)) {
recategorizations = new HashSet<>(convert(recategorizationPersistenceService.findEntriesByFileIdAndOptions(fileId, options),
ManualRecategorization.class,
new ManualImageRecategorizationMapper()));
} else {
recategorizations = Collections.emptySet();
}
if (!options.getExcludedClasses().contains(ManualResizeRedaction.class)) {
resizeRedactions = new HashSet<>(convert(resizeRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options),
ManualResizeRedaction.class,
new ManualResizeRedactionMapper()));
} else {
resizeRedactions = Collections.emptySet();
}
if (!options.getExcludedClasses().contains(IdRemoval.class)) {
removals = new HashSet<>(convert(removeRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options), IdRemoval.class));
} else {
removals = Collections.emptySet();
}
if (!options.getExcludedClasses().contains(ManualForceRedaction.class)) {
forceRedactions = new HashSet<>(convert(forceRedactionPersistenceService.findEntriesByFileIdAndOptions(fileId, options), ManualForceRedaction.class));
} else {
forceRedactions = Collections.emptySet();
}
if (!options.getExcludedClasses().contains(ManualLegalBasisChange.class)) {
legalBasisChanges = new HashSet<>(convert(legalBasisChangePersistenceService.findEntriesByFileIdAndOptions(fileId, options), ManualLegalBasisChange.class));
} else {
legalBasisChanges = Collections.emptySet();
}
return new ManualRedactions(removals, entriesToAdd, forceRedactions, recategorizations, legalBasisChanges, resizeRedactions);
}
private Set<ManualRedactionEntry> convertEntriesToAdd(List<ManualRedactionEntryEntity> source) {
return source.stream().map(entry -> convert(entry, ManualRedactionEntry.class, new ManualRedactionMapper())).collect(Collectors.toSet());
}

View File

@ -21,6 +21,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.annotati
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.RectangleEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.CommentService;
import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogMergeService;
import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService;
@ -108,13 +109,13 @@ public class ManualRedactionService {
response.add(ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).build());
}
manualRedactionEntryEntities = manualRedactionEntryEntities.stream()
.filter(manualRedactionEntry -> !manualRedactionEntry.isAddToDictionary() && !manualRedactionEntry.isAddToDossierDictionary())
var localManualRedactionEntryEntities = manualRedactionEntryEntities.stream()
.filter(manualRedactionEntry -> !manualRedactionEntry.isAddToDictionary() && !manualRedactionEntry.isAddToAllDossiers())
.collect(Collectors.toList());
FileModel fileStatus = fileStatusService.getStatus(fileId);
if (!manualRedactionEntryEntities.isEmpty() && fileStatus.isExcludedFromAutomaticAnalysis()) {
ManualRedactions manualRedactions = ManualRedactions.builder().entriesToAdd(convertEntriesToAdd(manualRedactionEntryEntities)).build();
if (!localManualRedactionEntryEntities.isEmpty() && fileStatus.isExcludedFromAutomaticAnalysis()) {
ManualRedactions manualRedactions = ManualRedactions.builder().entriesToAdd(convertEntriesToAdd(localManualRedactionEntryEntities)).build();
entityLogMergeService.sendToAnalyseQueue(fileId, dossierEntity, fileStatusService.getStatus(fileId), manualRedactions);
} else {
reprocess(dossierId, fileId);
@ -332,9 +333,9 @@ public class ManualRedactionService {
}
public ManualRedactions getManualRedactions(String fileId, boolean unprocessed) {
public ManualRedactions getManualRedactions(String fileId, ManualChangesQueryOptions options) {
return manualRedactionProviderService.getManualRedactions(fileId, unprocessed);
return manualRedactionProviderService.getManualRedactions(fileId, options);
}
@ -343,48 +344,43 @@ public class ManualRedactionService {
if (manualRedactions != null) {
if (manualRedactions.getEntriesToAdd() != null) {
manualRedactions.getEntriesToAdd().forEach(e -> {
if (e.getProcessedDate() == null) {
addRedactionPersistenceService.markAsProcessed(e);
}
});
}
if (manualRedactions.getIdsToRemove() != null) {
manualRedactions.getIdsToRemove().forEach(e -> {
if (e.getProcessedDate() == null) {
removeRedactionPersistenceService.markAsProcessed(e);
}
});
}
if (manualRedactions.getForceRedactions() != null) {
manualRedactions.getForceRedactions().forEach(e -> {
if (e.getProcessedDate() == null) {
forceRedactionPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId());
}
});
}
if (manualRedactions.getRecategorizations() != null) {
manualRedactions.getRecategorizations().forEach(e -> {
if (e.getProcessedDate() == null) {
recategorizationPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId());
}
});
}
if (manualRedactions.getResizeRedactions() != null) {
manualRedactions.getResizeRedactions().forEach(e -> {
if (e.getProcessedDate() == null) {
resizeRedactionPersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId());
}
});
}
if (manualRedactions.getLegalBasisChanges() != null) {
manualRedactions.getLegalBasisChanges().forEach(e -> {
if (e.getProcessedDate() == null) {
legalBasisChangePersistenceService.markAsProcessed(e.getAnnotationId(), e.getFileId());
}
});
}
}
}

View File

@ -21,6 +21,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.annotati
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRecategorizationEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
@ -96,7 +97,7 @@ public class ManualRedactionUndoService {
private ManualRedactions getManualRedactions(String fileId) {
return manualRedactionProviderService.getManualRedactions(fileId);
return manualRedactionProviderService.getManualRedactions(fileId, ManualChangesQueryOptions.allWithoutDeleted());
}

View File

@ -0,0 +1,197 @@
package com.iqser.red.service.persistence.management.v1.processor.service.manualredactions;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Engine;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ManualChange;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ManualRedactionType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle;
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.ManualRecategorization;
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;
@Service
public class PendingDictionaryEntryFactory {
public EntityLogEntry buildAddToDictionaryEntry(ManualRedactionEntry manualRedactionEntry) {
var manualChanges = List.of(ManualChange.builder()
.manualRedactionType(ManualRedactionType.ADD_TO_DICTIONARY)
.requestedDate(manualRedactionEntry.getRequestDate())
.processedDate(null)
.userId(manualRedactionEntry.getUser())
.propertyChanges(Map.of("value", manualRedactionEntry.getValue()))
.build());
return EntityLogEntry.builder()
.id(manualRedactionEntry.getAnnotationId())
.value(manualRedactionEntry.getValue())
.type(manualRedactionEntry.getType())
.entryType(manualRedactionEntry.getDictionaryEntryType().toEntryType())
.state(EntryState.PENDING)
.dictionaryEntry(manualRedactionEntry.isAddToDictionary())
.dossierDictionaryEntry(manualRedactionEntry.isAddToDossierDictionary())
.reason("Pending add to dictionary.")
.legalBasis("Pending add to dictionary.")
.matchedRule("")
.containingNodeId(Collections.emptyList())
.closestHeadline("")
.section("")
.positions(convertPositions(manualRedactionEntry.getPositions()))
.textAfter("")
.textBefore("")
.startOffset(-1)
.endOffset(-1)
.changes(Collections.emptyList())
.manualChanges(manualChanges)
.engines(Set.of(Engine.DICTIONARY))
.reference(Collections.emptySet())
.importedRedactionIntersections(Collections.emptySet())
.build();
}
private List<Position> convertPositions(List<Rectangle> rectangles) {
return rectangles.stream()
.map(rectangle -> new Position(rectangle.getTopLeftX(), rectangle.getTopLeftY(), rectangle.getWidth(), rectangle.getHeight(), rectangle.getPage()))
.collect(Collectors.toList());
}
public EntityLogEntry buildRemoveFromDictionary(IdRemoval manualChange, EntityLogEntry originalEntry) {
var manualChanges = List.of(ManualChange.builder()
.manualRedactionType(ManualRedactionType.REMOVE_FROM_DICTIONARY)
.requestedDate(manualChange.getRequestDate())
.processedDate(manualChange.getProcessedDate())
.userId(manualChange.getUser())
.propertyChanges(Map.of("remove", originalEntry.getValue()))
.build());
return EntityLogEntry.builder()
.id(originalEntry.getId())
.value(originalEntry.getValue())
.type(originalEntry.getType())
.entryType(originalEntry.getEntryType())
.state(EntryState.PENDING)
.dictionaryEntry(manualChange.isRemoveFromDictionary())
.dossierDictionaryEntry(!manualChange.isRemoveFromAllDossiers())
.reason("Pending remove from dictionary.")
.legalBasis("Pending remove from dictionary.")
.matchedRule("")
.containingNodeId(Collections.emptyList())
.closestHeadline("")
.section("")
.positions(originalEntry.getPositions())
.textAfter("")
.textBefore("")
.startOffset(-1)
.endOffset(-1)
.changes(Collections.emptyList())
.manualChanges(manualChanges)
.engines(Set.of(Engine.DICTIONARY))
.reference(Collections.emptySet())
.importedRedactionIntersections(Collections.emptySet())
.build();
}
public EntityLogEntry buildResizeWithDictionary(ManualResizeRedaction manualChange, EntityLogEntry originalEntry) {
Map<String, String> propertyChanges = buildPropertyChangesForManualResize(manualChange, originalEntry);
var manualChanges = List.of(ManualChange.builder()
.manualRedactionType(ManualRedactionType.RESIZE_IN_DICTIONARY)
.requestedDate(manualChange.getRequestDate())
.processedDate(manualChange.getProcessedDate())
.userId(manualChange.getUser())
.propertyChanges(propertyChanges)
.build());
return EntityLogEntry.builder()
.id(originalEntry.getId())
.value(manualChange.getValue())
.type(originalEntry.getType())
.entryType(originalEntry.getEntryType())
.state(EntryState.PENDING)
.dictionaryEntry(manualChange.getUpdateDictionary())
.dossierDictionaryEntry(!manualChange.isAddToAllDossiers())
.reason("Pending resize with dictionary.")
.legalBasis("Pending resize with dictionary.")
.matchedRule("")
.containingNodeId(Collections.emptyList())
.closestHeadline("")
.section("")
.positions(convertPositions(manualChange.getPositions()))
.textAfter("")
.textBefore("")
.startOffset(-1)
.endOffset(-1)
.changes(Collections.emptyList())
.manualChanges(manualChanges)
.engines(Set.of(Engine.DICTIONARY))
.reference(Collections.emptySet())
.importedRedactionIntersections(Collections.emptySet())
.build();
}
private static Map<String, String> buildPropertyChangesForManualResize(ManualResizeRedaction manualChange, EntityLogEntry originalEntry) {
Map<String, String> prop;
if (manualChange.getValue().length() >= originalEntry.getValue().length()) {
prop = Map.of("add", manualChange.getValue());
} else {
prop = Map.of("add", manualChange.getValue(), "remove", originalEntry.getValue());
}
return prop;
}
public EntityLogEntry buildRecategorizeWithDictionary(ManualRecategorization manualChange, EntityLogEntry originalEntry) {
var manualChanges = List.of(ManualChange.builder()
.manualRedactionType(ManualRedactionType.RECATEGORIZE_IN_DICTIONARY)
.requestedDate(manualChange.getRequestDate())
.processedDate(manualChange.getProcessedDate())
.userId(manualChange.getUser())
.propertyChanges(Map.of("type", manualChange.getType()))
.build());
return EntityLogEntry.builder()
.id(originalEntry.getId())
.value(originalEntry.getValue())
.type(manualChange.getType())
.entryType(originalEntry.getEntryType())
.state(EntryState.PENDING)
.dictionaryEntry(manualChange.isAddToDictionary())
.dossierDictionaryEntry(!manualChange.isAddToAllDossiers())
.reason("Pending recategorize with dictionary.")
.legalBasis("Pending recategorize with dictionary.")
.matchedRule("")
.containingNodeId(Collections.emptyList())
.closestHeadline("")
.section("")
.positions(originalEntry.getPositions())
.textAfter("")
.textBefore("")
.startOffset(-1)
.endOffset(-1)
.changes(Collections.emptyList())
.manualChanges(manualChanges)
.engines(Set.of(Engine.DICTIONARY))
.reference(Collections.emptySet())
.importedRedactionIntersections(Collections.emptySet())
.build();
}
}

View File

@ -1,6 +1,9 @@
package com.iqser.red.service.persistence.management.v1.processor.service.persistence;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId;
import java.util.List;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.entity.migration.SaasMigrationStatusEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.SaasMigrationStatusRepository;
@ -9,10 +12,6 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class SaasMigrationStatusPersistenceService {

View File

@ -15,6 +15,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.annotati
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.RectangleEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.ManualRedactionRepository;
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.Rectangle;
@ -79,9 +80,9 @@ public class AddRedactionPersistenceService {
}
public List<ManualRedactionEntryEntity> findAddRedactions(String fileId, boolean includeDeletions) {
public List<ManualRedactionEntryEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
return manualRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions);
return manualRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
}
@ -91,12 +92,6 @@ public class AddRedactionPersistenceService {
}
public List<ManualRedactionEntryEntity> findUnprocessedRedactions(String fileId) {
return manualRedactionRepository.findByFileIdAndUnprocessed(fileId);
}
@Transactional
public void hardDelete(String fileId, String annotationId) {

View File

@ -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.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.BeanUtils;
@ -12,6 +13,7 @@ import org.springframework.transaction.annotation.Transactional;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualForceRedactionEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.ForceRedactionRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ForceRedactionRequest;
@ -35,6 +37,10 @@ public class ForceRedactionPersistenceService {
forceRedactionRepository.saveAndFlush(manualForceRedaction);
}
public List<ManualForceRedactionEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
return forceRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed());
}
@Transactional
public void hardDelete(String fileId, String annotationId) {
@ -64,13 +70,13 @@ public class ForceRedactionPersistenceService {
}
public Set<ManualForceRedactionEntity> findForceRedactions(String fileId, boolean includeDeletions) {
public Set<ManualForceRedactionEntity> findForceRedactions(String fileId, boolean includeDeletions, boolean includeDictChanges) {
return new HashSet<>(forceRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions));
}
public Set<ManualForceRedactionEntity> findUnprocessedForceRedactions(String fileId) {
public Set<ManualForceRedactionEntity> findUnprocessedForceRedactions(String fileId, boolean includeDictChanges) {
return new HashSet<>(forceRedactionRepository.findByFileIdAndUnprocessed(fileId));
}

View File

@ -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.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
@ -14,6 +15,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.annotati
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualLegalBasisChangeEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.LegalBasisChangeRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.LegalBasisChangeRequest;
@ -78,7 +80,7 @@ public class LegalBasisChangePersistenceService {
}
public Set<ManualLegalBasisChangeEntity> findLegalBasisChanges(String fileId, boolean includeDeletions) {
public Set<ManualLegalBasisChangeEntity> findLegalBasisChanges(String fileId, boolean includeDeletions, boolean includeDictChanges) {
return new HashSet<>(legalBasisChangeRepository.findByFileIdIncludeDeletions(fileId, includeDeletions));
}
@ -95,4 +97,9 @@ public class LegalBasisChangePersistenceService {
legalBasisChangeRepository.markAsProcessed(new AnnotationEntityId(annotationId, fileId), OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
}
public List<ManualLegalBasisChangeEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
return legalBasisChangeRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed());
}
}

View File

@ -12,6 +12,7 @@ import org.springframework.transaction.annotation.Transactional;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRecategorizationEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.RecategorizationRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RecategorizationRequest;
@ -82,13 +83,19 @@ public class RecategorizationPersistenceService {
}
public List<ManualRecategorizationEntity> findRecategorizations(String fileId, boolean includeDeletions) {
public List<ManualRecategorizationEntity> findRecategorizations(String fileId, boolean includeDeletions, boolean includeDictChanges) {
return recategorizationRepository.findByFileIdIncludeDeletions(fileId, includeDeletions);
}
public List<ManualRecategorizationEntity> findUnprocessedRecategorizations(String fileId) {
public List<ManualRecategorizationEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
return recategorizationRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
}
public List<ManualRecategorizationEntity> findUnprocessedRecategorizations(String fileId, boolean includeDictChanges) {
return recategorizationRepository.findUnprocessedByFileId(fileId);
}

View File

@ -13,6 +13,7 @@ import org.springframework.transaction.annotation.Transactional;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.RemoveRedactionRepository;
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.entitymapped.IdRemoval;
@ -47,13 +48,13 @@ public class RemoveRedactionPersistenceService {
}
public Set<IdRemovalEntity> findRemoveRedactions(String fileId, boolean includeDeletions) {
public Set<IdRemovalEntity> findRemoveRedactions(String fileId, boolean includeDeletions, boolean includeDictChanges) {
return new HashSet<>(removeRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions));
}
public Set<IdRemovalEntity> findUnprocessedRemoveRedactions(String fileId) {
public Set<IdRemovalEntity> findUnprocessedRemoveRedactions(String fileId, boolean includeDictChanges) {
return new HashSet<>(removeRedactionRepository.findByFileIdAndUnprocessed(fileId));
}
@ -64,6 +65,10 @@ public class RemoveRedactionPersistenceService {
return removeRedactionRepository.findAll();
}
public List<IdRemovalEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
return removeRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
}
@Transactional
public void hardDelete(String fileId, String annotationId) {

View File

@ -14,6 +14,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.annotati
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualResizeRedactionEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.RectangleEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.model.ManualChangesQueryOptions;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.ResizeRedactionRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ResizeRedactionRequest;
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
@ -86,13 +87,14 @@ public class ResizeRedactionPersistenceService {
.orElseThrow(() -> new NotFoundException("Unknown file/annotation combination: " + fileId + "/" + annotationId));
}
public Optional<ManualResizeRedactionEntity> findResizeRedactionById(String fileId, String annotationId) {
return resizeRedactionRepository.findById(new AnnotationEntityId(annotationId, fileId));
}
public List<ManualResizeRedactionEntity> findResizeRedactions(String fileId, boolean includeDeletions) {
public List<ManualResizeRedactionEntity> findResizeRedactions(String fileId, boolean includeDeletions, boolean includeDictChanges) {
return resizeRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions);
}
@ -115,4 +117,10 @@ public class ResizeRedactionPersistenceService {
resizeRedactionRepository.markAsProcessed(new AnnotationEntityId(annotationId, fileId), OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
}
public List<ManualResizeRedactionEntity> findEntriesByFileIdAndOptions(String fileId, ManualChangesQueryOptions options) {
return resizeRedactionRepository.findByFileIdAndOptions(fileId, options.isIncludeDeletions(), options.isIncludeOnlyUnprocessed(), options.isIncludeDictChanges());
}
}

View File

@ -35,4 +35,14 @@ public interface ForceRedactionRepository extends JpaRepository<ManualForceRedac
@Query("update ManualForceRedactionEntity mfr set mfr.processedDate = :processedDate where mfr.id = :annotationEntityId")
void markAsProcessed(@Param("annotationEntityId") AnnotationEntityId annotationEntityId, @Param("processedDate") OffsetDateTime processedDate);
@Query("""
select m
from ManualForceRedactionEntity m
where m.id.fileId = :fileId
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
and (:includeDeletions = true or m.softDeletedTime is null)
""")
List<ManualForceRedactionEntity> findByFileIdAndOptions(@Param("fileId") String fileId,
@Param("includeDeletions") boolean includeDeletions,
@Param("unprocessed") boolean unprocessed);
}

View File

@ -35,4 +35,16 @@ public interface LegalBasisChangeRepository extends JpaRepository<ManualLegalBas
@Query("update ManualLegalBasisChangeEntity mlbc set mlbc.processedDate = :processedDate where mlbc.id = :annotationEntityId")
void markAsProcessed(@Param("annotationEntityId") AnnotationEntityId annotationEntityId, @Param("processedDate") OffsetDateTime processedDate);
@Query("""
select m
from ManualLegalBasisChangeEntity m
where m.id.fileId = :fileId
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
and (:includeDeletions = true or m.softDeletedTime is null)
""")
List<ManualLegalBasisChangeEntity> findByFileIdAndOptions(@Param("fileId") String fileId,
@Param("includeDeletions") boolean includeDeletions,
@Param("unprocessed") boolean unprocessed);
}

View File

@ -18,6 +18,7 @@ public interface ManualRedactionRepository extends JpaRepository<ManualRedaction
@Query("update ManualRedactionEntryEntity m set m.softDeletedTime = :softDeleteTime where m.id = :id")
void updateSoftDelete(@Param("id") AnnotationEntityId id, @Param("softDeleteTime") OffsetDateTime softDeleteTime);
@Modifying
@Query("update ManualRedactionEntryEntity m set m.addToDictionary = :isAddOrRemoveFromDictionary, m.addToDossierDictionary = :isAddOrRemoveFromDossierDictionary where m.id = :id")
void updateStatus(@Param("id") AnnotationEntityId id,
@ -37,6 +38,19 @@ public interface ManualRedactionRepository extends JpaRepository<ManualRedaction
List<ManualRedactionEntryEntity> findByFileIdAndUnprocessed(@Param("fileId") String fileId);
@Query("""
select m
from ManualRedactionEntryEntity m
where m.id.fileId = :fileId
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
and (:includeDeletions = true or m.softDeletedTime is null)
and (:includeDictChanges = true or (m.addToDictionary = false and m.addToAllDossiers = false))
""")
List<ManualRedactionEntryEntity> findByFileIdAndOptions(@Param("fileId") String fileId,
@Param("includeDeletions") boolean includeDeletions,
@Param("unprocessed") boolean unprocessed,
@Param("includeDictChanges") boolean includeDictChanges);
@Modifying
@Query("update ManualRedactionEntryEntity m set m.processedDate = :processedDate where m.id = :annotationEntityId")
void markAsProcessed(@Param("annotationEntityId") AnnotationEntityId annotationEntityId, @Param("processedDate") OffsetDateTime processedDate);

View File

@ -18,17 +18,35 @@ public interface RecategorizationRepository extends JpaRepository<ManualRecatego
@Query("update ManualRecategorizationEntity mir set mir.softDeletedTime = :softDeletedTime where mir.id = :annotationEntityId")
void updateSoftDelete(@Param("annotationEntityId") AnnotationEntityId annotationEntityId, @Param("softDeletedTime") OffsetDateTime softDeletedTime);
@Query("select mir from ManualRecategorizationEntity mir where mir.id = :annotationEntityId and mir.softDeletedTime is null")
Optional<ManualRecategorizationEntity> findByIdAndNotSoftDeleted(@Param("annotationEntityId") AnnotationEntityId annotationEntityId);
@Query("select mir from ManualRecategorizationEntity mir where mir.id.fileId = :fileId and (:includeDeletions = true or mir.softDeletedTime is null)")
List<ManualRecategorizationEntity> findByFileIdIncludeDeletions(@Param("fileId") String fileId, @Param("includeDeletions") boolean includeDeletions);
@Query("select mir from ManualRecategorizationEntity mir where mir.id.fileId = :fileId and mir.processedDate is null")
List<ManualRecategorizationEntity> findUnprocessedByFileId(@Param("fileId") String fileId);
@Modifying
@Query("update ManualRecategorizationEntity mir set mir.processedDate = :processedDate where mir.id = :annotationEntityId")
void markAsProcessed(@Param("annotationEntityId") AnnotationEntityId annotationEntityId, @Param("processedDate") OffsetDateTime processedDate);
@Query("""
select m
from ManualRecategorizationEntity m
where m.id.fileId = :fileId
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
and (:includeDeletions = true or m.softDeletedTime is null)
and (:includeDictChanges = true or (m.addToDictionary = false and m.addToAllDossiers = false))
""")
List<ManualRecategorizationEntity> findByFileIdAndOptions(@Param("fileId") String fileId,
@Param("includeDeletions") boolean includeDeletions,
@Param("unprocessed") boolean unprocessed,
@Param("includeDictChanges") boolean includeDictChanges);
}

View File

@ -32,4 +32,16 @@ public interface RemoveRedactionRepository extends JpaRepository<IdRemovalEntity
void markAsProcessed(@Param("annotationEntityId") AnnotationEntityId annotationEntityId, @Param("processedDate") OffsetDateTime processedDate);
@Query("""
select m
from IdRemovalEntity m
where m.id.fileId = :fileId
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
and (:includeDeletions = true or m.softDeletedTime is null)
and (:includeDictChanges = true or (m.removeFromDictionary = false and m.removeFromAllDossiers = false))
""")
List<IdRemovalEntity> findByFileIdAndOptions(@Param("fileId") String fileId,
@Param("includeDeletions") boolean includeDeletions,
@Param("unprocessed") boolean unprocessed,
@Param("includeDictChanges") boolean includeDictChanges);
}

View File

@ -43,4 +43,16 @@ public interface ResizeRedactionRepository extends JpaRepository<ManualResizeRed
@Query("update ManualResizeRedactionEntity mir set mir.processedDate = :processedDate where mir.id = :annotationEntityId")
void markAsProcessed(@Param("annotationEntityId") AnnotationEntityId annotationEntityId, @Param("processedDate") OffsetDateTime processedDate);
@Query("""
select m
from ManualResizeRedactionEntity m
where m.id.fileId = :fileId
and ((:unprocessed = true and m.processedDate is null) or :unprocessed = false)
and (:includeDeletions = true or m.softDeletedTime is null)
and (:includeDictChanges = true or (m.updateDictionary = false and m.addToAllDossiers = false))
""")
List<ManualResizeRedactionEntity> findByFileIdAndOptions(@Param("fileId") String fileId,
@Param("includeDeletions") boolean includeDeletions,
@Param("unprocessed") boolean unprocessed,
@Param("includeDictChanges") boolean includeDictChanges);
}

View File

@ -6,7 +6,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import java.time.OffsetDateTime;
@ -35,6 +34,7 @@ import com.iqser.red.service.persistence.management.v1.processor.service.EntityL
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService;
import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.PendingDictionaryEntryFactory;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
@ -95,7 +95,7 @@ public class EntityLogMergeTest {
@BeforeEach
public void setUp() {
entityLogMergeService = new EntityLogMergeService(dictionaryPersistenceService, rabbitTemplate, fileStatusService, fileStatusPersistenceService);
entityLogMergeService = new EntityLogMergeService(dictionaryPersistenceService, rabbitTemplate, fileStatusService, fileStatusPersistenceService, new PendingDictionaryEntryFactory());
}
@ -117,7 +117,7 @@ public class EntityLogMergeTest {
var entityLog = provideEntityLog(entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId);
when(manualRedactionProviderService.getManualRedactions(fileId, true)).thenReturn(manualRedactions);
when(manualRedactionProviderService.getManualRedactions(any(), any())).thenReturn(manualRedactions);
when(fileStatusService.getStatus(fileId)).thenReturn(FileModel.builder()
.excluded(false)
.dossierStatusId(dossierTemplateId)
@ -148,14 +148,14 @@ public class EntityLogMergeTest {
assertEquals(entityLogEntry.getReason(), "Reason");
assertTrue(entityLogEntry.getEngines().contains(Engine.MANUAL));
assertEquals(entityLogEntry.getManualChanges()
.get(0).getManualRedactionType(), ManualRedactionType.ADD_LOCALLY);
.get(0).getManualRedactionType(), ManualRedactionType.ADD);
var optionalRemoveEntryLogEntry = response.getEntityLogEntry().stream().filter(entityLogEntry1 -> entityLogEntry1.getId().equals(entryToRemoveId)).findFirst();
assertTrue(optionalRemoveEntryLogEntry.isPresent());
var removeEntryLogEntry = optionalRemoveEntryLogEntry.get();
assertEquals(removeEntryLogEntry.getEntryType(), EntryType.ENTITY);
assertEquals(removeEntryLogEntry.getState(), EntryState.IGNORED);
assertEquals(removeEntryLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.REMOVE_LOCALLY);
assertEquals(removeEntryLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.REMOVE);
assertEquals(removeEntryLogEntry.getChanges()
.get(0).getType(), ChangeType.REMOVED);
assertTrue(removeEntryLogEntry.getEngines().contains(Engine.MANUAL));
@ -192,7 +192,7 @@ public class EntityLogMergeTest {
assertEquals(forceRedactionEntryLogEntry.getLegalBasis(), "Force");
assertEquals(forceRedactionEntryLogEntry.getEntryType(), EntryType.ENTITY);
assertEquals(forceRedactionEntryLogEntry.getState(), EntryState.APPLIED);
assertEquals(forceRedactionEntryLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.FORCE_REDACT);
assertEquals(forceRedactionEntryLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.FORCE);
assertEquals(forceRedactionEntryLogEntry.getChanges()
.get(0).getType(), ChangeType.CHANGED);
assertTrue(forceRedactionEntryLogEntry.getEngines().contains(Engine.MANUAL));
@ -206,7 +206,7 @@ public class EntityLogMergeTest {
assertEquals(rectangleEntryLogEntry.getValue(), "Test2");
assertEquals(rectangleEntryLogEntry.getReason(), "Rectangle");
assertEquals(rectangleEntryLogEntry.getManualChanges()
.get(0).getManualRedactionType(), ManualRedactionType.ADD_LOCALLY);
.get(0).getManualRedactionType(), ManualRedactionType.ADD);
assertTrue(rectangleEntryLogEntry.getEngines().contains(Engine.MANUAL));
}

View File

@ -44,7 +44,10 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType;
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.ManualRedactions;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle;
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.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.AddRedactionRequestModel;
@ -457,7 +460,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
.build();
var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict));
var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false);
var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false, true);
var entityLog1 = new EntityLog(1,
1,
@ -516,7 +519,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
manualRedactionClient.resizeRedactionBulk(dossier1.getId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos), false);
loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false);
loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false, true);
assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1);
assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier dictionary");
@ -610,7 +613,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
.build();
var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict));
var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false);
var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false, true);
var entityLog1 = new EntityLog(1,
1,
@ -669,7 +672,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
manualRedactionClient.resizeRedactionBulk(dossier1.getId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos), false);
loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false);
loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false, true);
assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1);
assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier");
@ -723,7 +726,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
@Test
public void testEnlargeResizeRedactionInDossierTemplateDictionaryWithAddToAllDossiers() {
public void MtestEnlargeResizeRedactionInDossierTemplateDictionaryWithAddToAllDossiers() {
// preparíng prerequisites
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
@ -826,7 +829,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getId(), file2.getFileId(), Set.of(resizeRedactionDosTemp), false);
var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId(), false);
var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId(), false, true);
assertThat(loadedRedactionsFile2.getResizeRedactions()).hasSize(1);
assertThat(loadedRedactionsFile2.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier template dictionary");
@ -980,7 +983,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getId(), file2.getFileId(), Set.of(resizeRedactionDosTemp), false);
var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId(), false);
var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId(), false, true);
assertThat(loadedRedactionsFile2.getResizeRedactions()).hasSize(1);
assertThat(loadedRedactionsFile2.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier template");
@ -1216,11 +1219,11 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
.sourceId("SourceId")
.build()));
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getEntriesToAdd().size(), 1);
assertTrue(allManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Luke Skywalker")));
var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertEquals(unprocessedManualRedactions.getEntriesToAdd().size(), 1);
assertTrue(unprocessedManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Luke Skywalker")));
@ -1249,12 +1252,12 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
.sourceId("SourceId")
.build()));
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getEntriesToAdd().size(), 2);
assertTrue(allManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Skywalker Luke")));
assertTrue(allManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Luke Skywalker")));
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertEquals(unprocessedManualRedactions.getEntriesToAdd().size(), 1);
assertTrue(unprocessedManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Skywalker Luke")));
assertTrue(unprocessedManualRedactions.getEntriesToAdd().stream().noneMatch(entry -> entry.getValue().equals("Luke Skywalker")));
@ -1269,12 +1272,12 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
.dossierId(dossier.getId())
.build());
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getEntriesToAdd().size(), 2);
assertTrue(allManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Skywalker Luke")));
assertTrue(allManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Luke Skywalker")));
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertTrue(unprocessedManualRedactions.getEntriesToAdd().isEmpty());
dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getId(), DictionaryEntryType.ENTRY);
@ -1323,11 +1326,11 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
file.getId(),
Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build()), false);
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getIdsToRemove().size(), 1);
assertTrue(allManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId")));
var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertEquals(unprocessedManualRedactions.getIdsToRemove().size(), 1);
assertTrue(unprocessedManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId")));
@ -1345,12 +1348,12 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
file.getId(),
Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId2").removeFromDictionary(true).removeFromAllDossiers(true).build()), false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getIdsToRemove().size(), 2);
assertTrue(allManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId")));
assertTrue(allManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId2")));
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertEquals(unprocessedManualRedactions.getIdsToRemove().size(), 1);
assertTrue(unprocessedManualRedactions.getIdsToRemove().stream().noneMatch(entry -> entry.getAnnotationId().equals("AnnotationId")));
assertTrue(unprocessedManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId2")));
@ -1365,12 +1368,12 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
.dossierId(dossier.getId())
.build());
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getIdsToRemove().size(), 2);
assertTrue(allManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId")));
assertTrue(allManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId2")));
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertTrue(unprocessedManualRedactions.getIdsToRemove().isEmpty());
}
@ -1386,11 +1389,11 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
file.getId(),
Set.of(ForceRedactionRequestModel.builder().annotationId("forceRedactionAnnotation").comment("comment").legalBasis("1").build()));
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getForceRedactions().size(), 1);
assertTrue(allManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation")));
var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertEquals(unprocessedManualRedactions.getForceRedactions().size(), 1);
assertTrue(unprocessedManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation")));
@ -1408,12 +1411,12 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
file.getId(),
Set.of(ForceRedactionRequestModel.builder().annotationId("forceRedactionAnnotation2").comment("comment").legalBasis("1").build()));
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getForceRedactions().size(), 2);
assertTrue(allManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation")));
assertTrue(allManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation")));
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertEquals(unprocessedManualRedactions.getForceRedactions().size(), 1);
assertTrue(unprocessedManualRedactions.getForceRedactions().stream().noneMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation")));
assertTrue(unprocessedManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation2")));
@ -1428,12 +1431,12 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
.dossierId(dossier.getId())
.build());
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getForceRedactions().size(), 2);
assertTrue(allManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation")));
assertTrue(allManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation2")));
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertTrue(unprocessedManualRedactions.getForceRedactions().isEmpty());
}
@ -1479,11 +1482,11 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
manualRedactionClient.recategorizeBulk(dossier.getId(), file.getId(), Set.of(RecategorizationRequestModel.builder().annotationId("dv").build()),
false);
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getRecategorizations().size(), 1);
assertTrue(allManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv")));
var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertEquals(unprocessedManualRedactions.getRecategorizations().size(), 1);
assertTrue(unprocessedManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv")));
@ -1500,12 +1503,12 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
manualRedactionClient.recategorizeBulk(dossier.getId(), file.getId(), Set.of(RecategorizationRequestModel.builder().annotationId("dv2").build()),
false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getRecategorizations().size(), 2);
assertTrue(allManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv")));
assertTrue(allManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv2")));
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertEquals(unprocessedManualRedactions.getRecategorizations().size(), 1);
assertTrue(unprocessedManualRedactions.getRecategorizations().stream().noneMatch(entry -> entry.getAnnotationId().equals("dv")));
assertTrue(unprocessedManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv2")));
@ -1520,12 +1523,12 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
.dossierId(dossier.getId())
.build());
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getRecategorizations().size(), 2);
assertTrue(allManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv")));
assertTrue(allManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv2")));
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertTrue(unprocessedManualRedactions.getRecategorizations().isEmpty());
}
@ -1572,11 +1575,11 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
file.getId(),
Set.of(LegalBasisChangeRequestModel.builder().legalBasis("legalBasis").annotationId("AnnotationId").build()));
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getLegalBasisChanges().size(), 1);
assertTrue(allManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis")));
var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertEquals(unprocessedManualRedactions.getLegalBasisChanges().size(), 1);
assertTrue(unprocessedManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis")));
@ -1594,12 +1597,12 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
file.getId(),
Set.of(LegalBasisChangeRequestModel.builder().legalBasis("legalBasis2").annotationId("AnnotationId2").build()));
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getLegalBasisChanges().size(), 2);
assertTrue(allManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis")));
assertTrue(allManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis2")));
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertEquals(unprocessedManualRedactions.getLegalBasisChanges().size(), 1);
assertTrue(unprocessedManualRedactions.getLegalBasisChanges().stream().noneMatch(entry -> entry.getLegalBasis().equals("legalBasis")));
assertTrue(unprocessedManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis2")));
@ -1614,13 +1617,91 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest {
.dossierId(dossier.getId())
.build());
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false);
allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, true);
assertEquals(allManualRedactions.getLegalBasisChanges().size(), 2);
assertTrue(allManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis")));
assertTrue(allManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis2")));
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true);
unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertTrue(unprocessedManualRedactions.getResizeRedactions().isEmpty());
}
@Test
public void testQueryOptions() {
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate);
var file = fileTesterAndProvider.testAndProvideFile(dossier);
var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", false);
dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getId(), DictionaryEntryType.ENTRY);
var entityLog = new EntityLog(1,
1,
List.of(EntityLogEntry.builder()
.id("AnnotationId")
.type(type.getType())
.value("Luke Skywalker")
.entryType(EntryType.ENTITY)
.state(EntryState.APPLIED)
.dictionaryEntry(false)
.build(),
EntityLogEntry.builder()
.id("AnnotationId2")
.type(type.getType())
.value("Skywalker Luke")
.entryType(EntryType.ENTITY)
.state(EntryState.APPLIED)
.dictionaryEntry(false)
.build()),
null,
0,
0,
0,
0);
fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog);
when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog);
manualRedactionClient.legalBasisChangeBulk(dossier.getId(),
file.getId(),
Set.of(LegalBasisChangeRequestModel.builder().legalBasis("legalBasis").annotationId("AnnotationId").build()));
manualRedactionClient.addRedactionBulk(dossier.getId(),
file.getId(),
Set.of(AddRedactionRequestModel.builder()
.value("Peter")
.type("type")
.legalBasis("legalBasis")
.reason("reason")
.positions(List.of(new Rectangle(new Point(0, 0), 10, 10, 1)))
.dictionaryEntryType(DictionaryEntryType.ENTRY)
.addToDictionary(true)
.build()));
var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false, false);
assertEquals(allManualRedactions.getLegalBasisChanges().size(), 1);
assertTrue(allManualRedactions.getLegalBasisChanges()
.stream()
.anyMatch(entry -> entry.getLegalBasis().equals("legalBasis")));
var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, false);
assertEquals(unprocessedManualRedactions.buildAll().size(), 1);
assertTrue(unprocessedManualRedactions.getLegalBasisChanges()
.stream()
.anyMatch(entry -> entry.getLegalBasis().equals("legalBasis")));
var unprocessedManualRedactionsWithDict = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true, true);
assertEquals(unprocessedManualRedactionsWithDict.buildAll().size(), 2);
assertTrue(unprocessedManualRedactionsWithDict.getLegalBasisChanges()
.stream()
.anyMatch(entry -> entry.getLegalBasis().equals("legalBasis")));
assertTrue(unprocessedManualRedactionsWithDict.getEntriesToAdd()
.stream()
.anyMatch(entry -> entry.getValue().equals("Peter")));
}
}

View File

@ -1,14 +1,24 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
public enum ManualRedactionType {
@Deprecated
ADD_LOCALLY,
ADD_TO_DICTIONARY,
REMOVE_LOCALLY,
REMOVE_FROM_DICTIONARY,
@Deprecated
FORCE_REDACT,
@Deprecated
FORCE_HINT,
@Deprecated
REMOVE_LOCALLY,
ADD,
ADD_TO_DICTIONARY,
REMOVE,
REMOVE_FROM_DICTIONARY,
FORCE,
RECATEGORIZE,
RECATEGORIZE_IN_DICTIONARY,
LEGAL_BASIS_CHANGE,
RESIZE, // Treat internally as a local resize. Documine already has documents with the value "RESIZE" in them, so we need it for backwards compatibility
RESIZE,
RESIZE_IN_DICTIONARY
}

View File

@ -1,11 +1,12 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.BaseAnnotation;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.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.ManualLegalBasisChange;
@ -17,6 +18,7 @@ import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
@Data
@Builder
@ -24,22 +26,60 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
public class ManualRedactions {
@NonNull
@Builder.Default
private Set<IdRemoval> idsToRemove = new HashSet<>();
@NonNull
@Builder.Default
private Set<ManualRedactionEntry> entriesToAdd = new HashSet<>();
@NonNull
@Builder.Default
private Set<ManualForceRedaction> forceRedactions = new HashSet<>();
@NonNull
@Builder.Default
private Set<ManualRecategorization> recategorizations = new HashSet<>();
@NonNull
@Builder.Default
private Set<ManualLegalBasisChange> legalBasisChanges = new HashSet<>();
@NonNull
@Builder.Default
private Set<ManualResizeRedaction> resizeRedactions = new HashSet<>();
public List<BaseAnnotation> buildAll() {
List<BaseAnnotation> all = new ArrayList<>(idsToRemove.size()
+ entriesToAdd.size()
+ forceRedactions.size()
+ recategorizations.size()
+ legalBasisChanges.size()
+ resizeRedactions.size());
all.addAll(idsToRemove);
all.addAll(entriesToAdd);
all.addAll(forceRedactions);
all.addAll(recategorizations);
all.addAll(legalBasisChanges);
all.addAll(resizeRedactions);
return all;
}
public List<BaseAnnotation> buildAllSorted() {
return buildAll().stream()
.sorted(Comparator.comparing(BaseAnnotation::getRequestDate))
.toList();
}
public boolean isEmpty() {
return idsToRemove.isEmpty()
&& entriesToAdd.isEmpty()
&& forceRedactions.isEmpty()
&& recategorizations.isEmpty()
&& legalBasisChanges.isEmpty()
&& resizeRedactions.isEmpty();
}
}

View File

@ -2,8 +2,6 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.annotation
import java.time.OffsetDateTime;
import org.checkerframework.checker.units.qual.A;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
import lombok.AllArgsConstructor;
@ -17,7 +15,7 @@ import lombok.experimental.SuperBuilder;
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class BaseAnnotation {
public abstract class BaseAnnotation {
private String annotationId;
private String fileId;
@ -26,6 +24,7 @@ public class BaseAnnotation {
private OffsetDateTime processedDate;
private OffsetDateTime softDeletedTime;
public abstract boolean isLocal();
@Deprecated(forRemoval = true)
public boolean isApproved() {

View File

@ -16,4 +16,11 @@ public class IdRemoval extends BaseAnnotation {
private boolean removeFromDictionary;
private boolean removeFromAllDossiers;
@Override
public boolean isLocal() {
return !(removeFromDictionary || removeFromAllDossiers);
}
}

View File

@ -15,4 +15,11 @@ public class ManualForceRedaction extends BaseAnnotation {
private String legalBasis;
@Override
public boolean isLocal() {
return true;
}
}

View File

@ -17,4 +17,11 @@ public class ManualLegalBasisChange extends BaseAnnotation {
private String value;
private String legalBasis;
@Override
public boolean isLocal() {
return true;
}
}

View File

@ -14,5 +14,15 @@ import lombok.experimental.SuperBuilder;
public class ManualRecategorization extends BaseAnnotation {
private String type;
private String legalBasis;
private boolean addToDictionary;
private boolean addToAllDossiers;
@Override
public boolean isLocal() {
return !(addToDictionary || addToAllDossiers);
}
}

View File

@ -33,4 +33,11 @@ public class ManualRedactionEntry extends BaseAnnotation {
private String sourceId;
private DictionaryEntryType dictionaryEntryType;
@Override
public boolean isLocal() {
return !(addToDictionary || addToDossierDictionary);
}
}

View File

@ -25,4 +25,11 @@ public class ManualResizeRedaction extends BaseAnnotation {
private Boolean updateDictionary;
private boolean addToAllDossiers;
@Override
public boolean isLocal() {
return !(updateDictionary || addToAllDossiers);
}
}

View File

@ -1,7 +1,27 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType;
public enum DictionaryEntryType {
ENTRY,
FALSE_POSITIVE,
FALSE_RECOMMENDATION
FALSE_POSITIVE {
@Override
public EntryType toEntryType() {
return EntryType.FALSE_POSITIVE;
}
},
FALSE_RECOMMENDATION {
@Override
public EntryType toEntryType() {
return EntryType.FALSE_RECOMMENDATION;
}
};
public EntryType toEntryType() {
return EntryType.ENTITY;
}
}