RED-7782 - Merge unprocessed redactions into entity log without re-analysis. #200
@ -27,9 +27,10 @@ public class EntityLogController implements EntityLogResource {
|
||||
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
|
||||
public EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes) {
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) {
|
||||
|
||||
return entityLogService.getEntityLog(dossierId, fileId, excludedTypes);
|
||||
return entityLogService.getEntityLog(dossierId, fileId, excludedTypes, includeUnprocessed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -29,13 +29,16 @@ public interface EntityLogResource {
|
||||
String DOSSIER_ID = "dossierId";
|
||||
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
|
||||
|
||||
String FALSE = "false";
|
||||
|
||||
@GetMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the entity log for a fileId", description = "None")
|
||||
@Operation(summary = "Gets the entity log for a fileId", description = "Gets the entity log for a given file. The flag includeUnprocessed will merge into the entity log all the unprocessed changes if it's set to true." +
|
||||
"Default value for the flag is false.")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entity log is not found.")})
|
||||
EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes);
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed);
|
||||
|
||||
|
||||
@PostMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE + "/filtered", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
|
||||
@ -21,9 +21,10 @@ public class EntityLogInternalController implements EntityLogResource {
|
||||
|
||||
public EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes) {
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) {
|
||||
|
||||
return entityLogService.getEntityLog(dossierId, fileId, excludedTypes);
|
||||
return entityLogService.getEntityLog(dossierId, fileId, excludedTypes, includeUnprocessed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -26,11 +26,14 @@ public interface EntityLogResource {
|
||||
String DOSSIER_ID = "dossierId";
|
||||
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
|
||||
|
||||
String FALSE = "false";
|
||||
|
||||
|
||||
@GetMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Operation(summary = "Gets the entity log for a fileId", description = "None")
|
||||
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entity log is not found.")})
|
||||
EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
|
||||
@PathVariable(FILE_ID) String fileId,
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes);
|
||||
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
|
||||
@RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed);
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.client.redactionservice;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
|
||||
import com.iqser.red.service.redaction.v1.resources.UnprocessedManualEntityResource;
|
||||
|
||||
@FeignClient(name = "UnprocessedManualEntityClient", url = "${redaction-service.url}")
|
||||
public interface UnprocessedManualEntityClient extends UnprocessedManualEntityResource {
|
||||
|
||||
}
|
||||
@ -1,39 +1,70 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service;
|
||||
|
||||
import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.UnprocessedManualEntityClient;
|
||||
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.ManualRedactionProviderService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Change;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ChangeType;
|
||||
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.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.analysislog.entitylog.FilteredEntityLogRequest;
|
||||
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.ManualRedactions;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.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.ManualRedactionEntry;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualResizeRedaction;
|
||||
import com.iqser.red.service.redaction.v1.model.UnprocessedManualEntity;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
|
||||
@Slf4j
|
||||
public class EntityLogService {
|
||||
|
||||
FileManagementStorageService fileManagementStorageService;
|
||||
FileStatusService fileStatusService;
|
||||
ManualRedactionProviderService manualRedactionProviderService;
|
||||
UnprocessedManualEntityClient unprocessedManualEntityClient;
|
||||
DossierService dossierService;
|
||||
CommentService commentService;
|
||||
DictionaryPersistenceService dictionaryPersistenceService;
|
||||
|
||||
|
||||
public EntityLog getEntityLog(String dossierId, String fileId) {
|
||||
|
||||
return getEntityLog(dossierId, fileId, Collections.emptyList());
|
||||
return getEntityLog(dossierId, fileId, Collections.emptyList(), false);
|
||||
}
|
||||
|
||||
|
||||
public EntityLog getEntityLog(String dossierId, String fileId, List<String> excludedTypes) {
|
||||
public EntityLog getEntityLog(String dossierId, String fileId, List<String> excludedTypes, boolean includeUnprocessed) {
|
||||
|
||||
var fileStatus = fileStatusService.getStatus(fileId);
|
||||
|
||||
@ -49,6 +80,13 @@ public class EntityLogService {
|
||||
entityLog.getEntityLogEntry().removeIf(entry -> excludedTypes.contains(entry.getType()));
|
||||
}
|
||||
|
||||
if (includeUnprocessed) {
|
||||
DossierEntity dossier = dossierService.getDossierById(dossierId);
|
||||
ManualRedactions manualRedactions = manualRedactionProviderService.getManualRedactions(fileId, true);
|
||||
List<UnprocessedManualEntity> unprocessedManualEntities = getUnprocessedManualEntities(dossierId, fileId, dossier.getDossierTemplateId(), manualRedactions);
|
||||
mergeEntityLog(manualRedactions, unprocessedManualEntities, entityLog, dossier.getDossierTemplateId());
|
||||
}
|
||||
|
||||
Map<String, Integer> commentCountPerAnnotationId = commentService.getCommentCounts(fileId);
|
||||
entityLog.getEntityLogEntry().forEach(entityLogEntry -> entityLogEntry.setNumberOfComments(commentCountPerAnnotationId.getOrDefault(entityLogEntry.getId(), 0)));
|
||||
|
||||
@ -62,7 +100,7 @@ public class EntityLogService {
|
||||
filteredEntityLogRequest.setSpecifiedDate(OffsetDateTime.MIN);
|
||||
}
|
||||
|
||||
var entityLog = getEntityLog(dossierId, fileId, filteredEntityLogRequest.getExcludedTypes());
|
||||
var entityLog = getEntityLog(dossierId, fileId, filteredEntityLogRequest.getExcludedTypes(), false);
|
||||
var entityLogEntry = entityLog.getEntityLogEntry();
|
||||
|
||||
Iterator<EntityLogEntry> it = entityLogEntry.iterator();
|
||||
@ -92,4 +130,194 @@ public class EntityLogService {
|
||||
return entityLog;
|
||||
}
|
||||
|
||||
private List<UnprocessedManualEntity> getUnprocessedManualEntities(String dossierId, String fileId, String dossierTemplateId, ManualRedactions manualRedactions) {
|
||||
|
||||
return unprocessedManualEntityClient.mergeUnprocessedManualEntities(fileId, dossierId, dossierTemplateId, manualRedactions);
|
||||
|
||||
}
|
||||
|
||||
public void mergeEntityLog(ManualRedactions manualRedactions, List<UnprocessedManualEntity> unprocessedManualEntities, EntityLog entityLog, String dossierTemplateId) {
|
||||
|
||||
log.info("Merging EntityLog");
|
||||
mergeManualRedactionEntries(manualRedactions.getEntriesToAdd(), unprocessedManualEntities, entityLog, dossierTemplateId);
|
||||
mergeIdsToRemove(manualRedactions.getIdsToRemove(), entityLog);
|
||||
mergeResizeRedactions(manualRedactions.getResizeRedactions(), entityLog);
|
||||
mergeLegalBasisChanges(manualRedactions.getLegalBasisChanges(), entityLog);
|
||||
mergeRecategorizations(manualRedactions.getRecategorizations(), entityLog);
|
||||
mergeForceRedactions(manualRedactions.getForceRedactions(), entityLog);
|
||||
log.info("EntityLog merged successfully!");
|
||||
}
|
||||
|
||||
|
||||
private void mergeManualRedactionEntries(Set<ManualRedactionEntry> manualRedactionEntries, List<UnprocessedManualEntity> unprocessedManualEntities, EntityLog entityLog, String dossierTemplateId) {
|
||||
|
||||
manualRedactionEntries.forEach(manualRedactionEntry -> {
|
||||
UnprocessedManualEntity unprocessedManualEntity = unprocessedManualEntities.stream()
|
||||
.filter(manualEntity -> manualEntity.getAnnotationId().equals(manualRedactionEntry.getAnnotationId()))
|
||||
.findFirst().orElseThrow(() -> new NotFoundException("Entry with annotationId " + manualRedactionEntry.getAnnotationId() + " not found"));
|
||||
List<Change> changes = new ArrayList<>();
|
||||
changes.add(Change.builder()
|
||||
.analysisNumber(entityLog.getAnalysisNumber())
|
||||
.dateTime(OffsetDateTime.now())
|
||||
.type(ChangeType.ADDED)
|
||||
.build());
|
||||
entityLog.getEntityLogEntry().add(EntityLogEntry.builder()
|
||||
.id(manualRedactionEntry.getAnnotationId())
|
||||
.type(manualRedactionEntry.getType())
|
||||
.value(manualRedactionEntry.getValue())
|
||||
.legalBasis(manualRedactionEntry.getLegalBasis())
|
||||
.reason(manualRedactionEntry.getReason())
|
||||
.entryType(isHint(manualRedactionEntry.getType(), dossierTemplateId) ? EntryType.HINT : EntryType.ENTITY)
|
||||
.imported(false)
|
||||
.matchedRule("")
|
||||
.section(manualRedactionEntry.getSection())
|
||||
.color(unprocessedManualEntity.getColor())
|
||||
.positions(unprocessedManualEntity.getPositions())
|
||||
.textAfter(unprocessedManualEntity.getTextAfter())
|
||||
.textBefore(unprocessedManualEntity.getTextBefore())
|
||||
.startOffset(unprocessedManualEntity.getStartOffset())
|
||||
.endOffset(unprocessedManualEntity.getEndOffset())
|
||||
.containingNodeId(unprocessedManualEntity.getContainingNodeId())
|
||||
.closestHeadline(unprocessedManualEntity.getClosestHeadline())
|
||||
.imageHasTransparency(false)
|
||||
.dictionaryEntry(manualRedactionEntry.isAddToDictionary())
|
||||
.dossierDictionaryEntry(manualRedactionEntry.isAddToDossierDictionary())
|
||||
.excluded(false)
|
||||
.changes(changes)
|
||||
.manualChanges(List.of(ManualChange.builder()
|
||||
.manualRedactionType(ManualRedactionType.ADD_LOCALLY)
|
||||
.requestedDate(manualRedactionEntry.getRequestDate())
|
||||
.processedDate(null)
|
||||
.userId(manualRedactionEntry.getUser())
|
||||
.propertyChanges(Map.of("value", manualRedactionEntry.getValue()))
|
||||
.build()))
|
||||
.engines(new HashSet<>())
|
||||
.reference(new HashSet<>())
|
||||
.importedRedactionIntersections(new HashSet<>())
|
||||
.build());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void mergeIdsToRemove(Set<IdRemoval> idRemovals, EntityLog entityLog) {
|
||||
|
||||
idRemovals.forEach(idRemoval -> {
|
||||
var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(idRemoval.getAnnotationId())).findAny();
|
||||
if (entity.isPresent()) {
|
||||
entity.get().setState(EntryState.IGNORED);
|
||||
addChanges(entity.get().getChanges(), ChangeType.REMOVED, entityLog.getAnalysisNumber());
|
||||
entity.get().getManualChanges().add(ManualChange.builder()
|
||||
.manualRedactionType(ManualRedactionType.REMOVE_LOCALLY)
|
||||
.requestedDate(idRemoval.getRequestDate())
|
||||
.processedDate(null)
|
||||
.userId(idRemoval.getUser()).build());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void mergeResizeRedactions(Set<ManualResizeRedaction> manualResizeRedactions, EntityLog entityLog) {
|
||||
|
||||
manualResizeRedactions.forEach(manualResizeRedaction -> {
|
||||
var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(manualResizeRedaction.getAnnotationId())).findAny();
|
||||
if (entity.isPresent()) {
|
||||
var newPosition = manualResizeRedaction.getPositions().get(0);
|
||||
entity.get().setPositions(List.of(new Position(
|
||||
newPosition.getTopLeftX(),
|
||||
newPosition.getTopLeftY(),
|
||||
newPosition.getWidth(),
|
||||
newPosition.getHeight(),
|
||||
newPosition.getPage())));
|
||||
addChanges(entity.get().getChanges(), ChangeType.CHANGED, entityLog.getAnalysisNumber());
|
||||
entity.get().getManualChanges().add(ManualChange.builder()
|
||||
.manualRedactionType(ManualRedactionType.RESIZE)
|
||||
.requestedDate(manualResizeRedaction.getRequestDate())
|
||||
.processedDate(null)
|
||||
.propertyChanges(Map.of("value", manualResizeRedaction.getValue()))
|
||||
.userId(manualResizeRedaction.getUser()).build());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void mergeLegalBasisChanges(Set<ManualLegalBasisChange> manualLegalBasisChanges, EntityLog entityLog) {
|
||||
|
||||
manualLegalBasisChanges.forEach(manualLegalBasisChange -> {
|
||||
var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(manualLegalBasisChange.getAnnotationId())).findAny();
|
||||
if (entity.isPresent()) {
|
||||
entity.get().setLegalBasis(manualLegalBasisChange.getLegalBasis());
|
||||
entity.get().setSection(manualLegalBasisChange.getSection());
|
||||
entity.get().setValue(manualLegalBasisChange.getValue());
|
||||
addChanges(entity.get().getChanges(), ChangeType.CHANGED, entityLog.getAnalysisNumber());
|
||||
entity.get().getManualChanges().add(ManualChange.builder()
|
||||
.manualRedactionType(ManualRedactionType.LEGAL_BASIS_CHANGE)
|
||||
.requestedDate(manualLegalBasisChange.getRequestDate())
|
||||
.processedDate(null)
|
||||
.propertyChanges(Map.of("value", manualLegalBasisChange.getValue(),
|
||||
"section", manualLegalBasisChange.getSection(),
|
||||
"legalBasis", manualLegalBasisChange.getLegalBasis()))
|
||||
.userId(manualLegalBasisChange.getUser())
|
||||
.build());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void mergeRecategorizations(Set<ManualRecategorization> recategorizations, EntityLog entityLog) {
|
||||
|
||||
recategorizations.forEach(recategorization -> {
|
||||
var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(recategorization.getAnnotationId())).findAny();
|
||||
if (entity.isPresent()) {
|
||||
entity.get().setType(recategorization.getType());
|
||||
addChanges(entity.get().getChanges(), ChangeType.CHANGED, entityLog.getAnalysisNumber());
|
||||
entity.get().getManualChanges().add(ManualChange.builder()
|
||||
.manualRedactionType(ManualRedactionType.RECATEGORIZE)
|
||||
.requestedDate(recategorization.getRequestDate())
|
||||
.processedDate(recategorization.getProcessedDate())
|
||||
.userId(recategorization.getUser())
|
||||
.propertyChanges(Map.of("type", recategorization.getType()))
|
||||
.build());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void mergeForceRedactions(Set<ManualForceRedaction> forceRedactions, EntityLog entityLog) {
|
||||
|
||||
forceRedactions.forEach(forceRedaction -> {
|
||||
var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(forceRedaction.getAnnotationId())).findAny();
|
||||
if (entity.isPresent()) {
|
||||
entity.get().setLegalBasis(forceRedaction.getLegalBasis());
|
||||
entity.get().setState(EntryState.APPLIED);
|
||||
addChanges(entity.get().getChanges(), ChangeType.CHANGED, entityLog.getAnalysisNumber());
|
||||
entity.get().getManualChanges().add(ManualChange.builder()
|
||||
.manualRedactionType(ManualRedactionType.FORCE_REDACT)
|
||||
.requestedDate(forceRedaction.getRequestDate())
|
||||
.processedDate(forceRedaction.getProcessedDate())
|
||||
.userId(forceRedaction.getUser())
|
||||
.propertyChanges(Map.of("legalBasis", forceRedaction.getLegalBasis()))
|
||||
.build());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addChanges(List<Change> changes, ChangeType changeType, int analysisNumber) {
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
changes.add(Change.builder()
|
||||
.analysisNumber(analysisNumber + 1)
|
||||
.dateTime(OffsetDateTime.now())
|
||||
.type(changeType)
|
||||
.build());
|
||||
} else {
|
||||
changes.add(Change.builder().analysisNumber(analysisNumber).dateTime(OffsetDateTime.now()).type(changeType).build());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isHint(String type, String dossierTemplateId) {
|
||||
|
||||
String typeId = toTypeId(type, dossierTemplateId);
|
||||
TypeEntity typeEntity = dictionaryPersistenceService.getType(typeId);
|
||||
if (typeEntity == null) {
|
||||
throw new NotFoundException("TypeEntity could not be found for typeId: " + typeId);
|
||||
}
|
||||
return typeEntity.isHint();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,280 @@
|
||||
package com.iqser.red.service.peristence.v1.server.integration.tests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.testcontainers.shaded.com.google.common.collect.Lists;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.UnprocessedManualEntityClient;
|
||||
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.service.CommentService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DossierService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService;
|
||||
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.persistence.DictionaryPersistenceService;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ChangeType;
|
||||
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.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.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.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.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;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRedactionEntry;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualResizeRedaction;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel;
|
||||
import com.iqser.red.service.redaction.v1.model.UnprocessedManualEntity;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
public class EntityLogTest {
|
||||
|
||||
@MockBean
|
||||
private FileStatusService fileStatusService;
|
||||
|
||||
@MockBean
|
||||
private FileManagementStorageService fileManagementStorageService;
|
||||
|
||||
@MockBean
|
||||
private DossierService dossierService;
|
||||
|
||||
@MockBean
|
||||
private CommentService commentService;
|
||||
|
||||
@MockBean
|
||||
private ManualRedactionProviderService manualRedactionProviderService;
|
||||
|
||||
@MockBean
|
||||
private UnprocessedManualEntityClient unprocessedManualEntityClient;
|
||||
|
||||
@MockBean
|
||||
private DictionaryPersistenceService dictionaryPersistenceService;
|
||||
|
||||
private EntityLogService entityLogService;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
|
||||
entityLogService = new EntityLogService(fileManagementStorageService, fileStatusService, manualRedactionProviderService, unprocessedManualEntityClient, dossierService, commentService, dictionaryPersistenceService);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetEntityLogWithUnprocessedRedactions() {
|
||||
|
||||
String fileId = "fileId";
|
||||
String dossierId = "dossierId";
|
||||
String dossierTemplateId = "dossierTemplateId";
|
||||
|
||||
String entryToAddId = UUID.randomUUID().toString();
|
||||
String entryToRemoveId = UUID.randomUUID().toString();
|
||||
String entryToResizeId = UUID.randomUUID().toString();
|
||||
String entryLegalBasisId = UUID.randomUUID().toString();
|
||||
String forceRedactionId = UUID.randomUUID().toString();
|
||||
|
||||
ManualRedactions manualRedactions = provideManualRedactions(entryToAddId, entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId, fileId);
|
||||
UnprocessedManualEntity unprocessedManualEntity = UnprocessedManualEntity.builder()
|
||||
.textBefore("textBefore")
|
||||
.textAfter("textAfter")
|
||||
.containingNodeId(List.of(0, 0))
|
||||
.endOffset(10)
|
||||
.startOffset(1)
|
||||
.annotationId(entryToAddId)
|
||||
.closestHeadline("closestHeadline")
|
||||
.color(new float[]{0,0,0})
|
||||
.build();
|
||||
|
||||
var entityLog = provideEntityLog(entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId);
|
||||
|
||||
when(manualRedactionProviderService.getManualRedactions(fileId, true)).thenReturn(manualRedactions);
|
||||
when(unprocessedManualEntityClient.mergeUnprocessedManualEntities(any(), any(), any(), any())).thenReturn(List.of(unprocessedManualEntity));
|
||||
when(fileStatusService.getStatus(fileId)).thenReturn(FileModel.builder()
|
||||
.excluded(false)
|
||||
.dossierStatusId(dossierTemplateId)
|
||||
.id(fileId)
|
||||
.build());
|
||||
when(fileManagementStorageService.getEntityLog(dossierId, fileId)).thenReturn(entityLog);
|
||||
when(dossierService.getDossierById(dossierId)).thenReturn(DossierEntity.builder()
|
||||
.dossierTemplateId(dossierTemplateId)
|
||||
.build());
|
||||
when(dictionaryPersistenceService.getType(anyString())).thenReturn(TypeEntity.builder().isHint(false).build());
|
||||
|
||||
EntityLog response = entityLogService.getEntityLog(dossierId, fileId, null, true);
|
||||
|
||||
assertNotNull(response);
|
||||
assertFalse(response.getEntityLogEntry().isEmpty());
|
||||
|
||||
var optionalEntityLogEntry = response.getEntityLogEntry().stream().filter(entityLogEntry1 -> entityLogEntry1.getId().equals(entryToAddId)).findFirst();
|
||||
assertTrue(optionalEntityLogEntry.isPresent());
|
||||
var entityLogEntry = optionalEntityLogEntry.get();
|
||||
assertEquals(entityLogEntry.getType(), "manual");
|
||||
assertEquals(entityLogEntry.getEntryType(), EntryType.ENTITY);
|
||||
assertNull(entityLogEntry.getState());
|
||||
assertEquals(entityLogEntry.getValue(), "Test");
|
||||
assertEquals(entityLogEntry.getReason(), "Reason");
|
||||
assertEquals(entityLogEntry.getTextAfter(), "textAfter");
|
||||
assertEquals(entityLogEntry.getTextBefore(), "textBefore");
|
||||
assertEquals(entityLogEntry.getStartOffset(), 1);
|
||||
assertEquals(entityLogEntry.getEndOffset(), 10);
|
||||
assertEquals(entityLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.ADD_LOCALLY);
|
||||
|
||||
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.getChanges().get(0).getType(), ChangeType.REMOVED);
|
||||
|
||||
var optionalResizeEntryLogEntry = response.getEntityLogEntry().stream().filter(entityLogEntry1 -> entityLogEntry1.getId().equals(entryToResizeId)).findFirst();
|
||||
assertTrue(optionalResizeEntryLogEntry.isPresent());
|
||||
var resizeEntryLogEntry = optionalResizeEntryLogEntry.get();
|
||||
assertEquals(resizeEntryLogEntry.getPositions().get(0).getRectangle()[0], 2);
|
||||
assertEquals(resizeEntryLogEntry.getPositions().get(0).getRectangle()[1], 2);
|
||||
assertEquals(resizeEntryLogEntry.getPositions().get(0).getRectangle()[2], 2);
|
||||
assertEquals(resizeEntryLogEntry.getPositions().get(0).getRectangle()[3], 2);
|
||||
assertEquals(resizeEntryLogEntry.getPositions().get(0).getPageNumber(), 1);
|
||||
assertEquals(resizeEntryLogEntry.getEntryType(), EntryType.ENTITY);
|
||||
assertEquals(resizeEntryLogEntry.getState(), EntryState.APPLIED);
|
||||
assertEquals(resizeEntryLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.RESIZE);
|
||||
assertEquals(resizeEntryLogEntry.getChanges().get(0).getType(), ChangeType.CHANGED);
|
||||
|
||||
var optionalLegalBasisEntryLogEntry = response.getEntityLogEntry().stream().filter(entityLogEntry1 -> entityLogEntry1.getId().equals(entryLegalBasisId)).findFirst();
|
||||
assertTrue(optionalLegalBasisEntryLogEntry.isPresent());
|
||||
var legalBasisEntryLogEntry = optionalLegalBasisEntryLogEntry.get();
|
||||
assertEquals(legalBasisEntryLogEntry.getLegalBasis(), "New legal basis");
|
||||
assertEquals(legalBasisEntryLogEntry.getEntryType(), EntryType.ENTITY);
|
||||
assertEquals(legalBasisEntryLogEntry.getState(), EntryState.APPLIED);
|
||||
assertEquals(legalBasisEntryLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.LEGAL_BASIS_CHANGE);
|
||||
assertEquals(legalBasisEntryLogEntry.getChanges().get(0).getType(), ChangeType.CHANGED);
|
||||
|
||||
var optionalForceRedactionEntryLogEntry = response.getEntityLogEntry().stream().filter(entityLogEntry1 -> entityLogEntry1.getId().equals(forceRedactionId)).findFirst();
|
||||
assertTrue(optionalForceRedactionEntryLogEntry.isPresent());
|
||||
var forceRedactionEntryLogEntry = optionalForceRedactionEntryLogEntry.get();
|
||||
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.getChanges().get(0).getType(), ChangeType.CHANGED);
|
||||
|
||||
}
|
||||
|
||||
private EntityLog provideEntityLog(String entryToRemoveId, String entryToResizeId, String entryLegalBasisId, String forceRedactionId) {
|
||||
|
||||
List<Position> positions = new ArrayList<>();
|
||||
positions.add(new Position(1, 1, 1, 1, 1));
|
||||
return new EntityLog(1,
|
||||
1,
|
||||
Lists.newArrayList(EntityLogEntry.builder()
|
||||
.id(entryToRemoveId)
|
||||
.type("manual")
|
||||
.value("Luke Skywalker")
|
||||
.entryType(EntryType.ENTITY)
|
||||
.state(EntryState.APPLIED)
|
||||
.dictionaryEntry(true)
|
||||
.build(),
|
||||
EntityLogEntry.builder()
|
||||
.id(entryToResizeId)
|
||||
.type("manual")
|
||||
.value("Darth Vader")
|
||||
.entryType(EntryType.ENTITY)
|
||||
.state(EntryState.APPLIED)
|
||||
.dictionaryEntry(true)
|
||||
.positions(positions)
|
||||
.build(),
|
||||
EntityLogEntry.builder()
|
||||
.id(entryLegalBasisId)
|
||||
.type("manual")
|
||||
.value("Darth Luke")
|
||||
.entryType(EntryType.ENTITY)
|
||||
.state(EntryState.APPLIED)
|
||||
.dictionaryEntry(true)
|
||||
.positions(positions)
|
||||
.build(),
|
||||
EntityLogEntry.builder()
|
||||
.id(forceRedactionId)
|
||||
.type("manual")
|
||||
.value("Darth Luke")
|
||||
.entryType(EntryType.ENTITY)
|
||||
.state(EntryState.APPLIED)
|
||||
.dictionaryEntry(true)
|
||||
.positions(positions)
|
||||
.build()),
|
||||
null,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
private ManualRedactions provideManualRedactions(String entryToAddId, String entryToRemoveId, String entryToResizeId, String entryLegalBasisId, String forceRedactionId, String fileId) {
|
||||
|
||||
List<Rectangle> positions = new ArrayList<>();
|
||||
positions.add(new Rectangle(2, 2, 2, 2, 1));
|
||||
return ManualRedactions.builder()
|
||||
.entriesToAdd(Set.of(
|
||||
ManualRedactionEntry.builder()
|
||||
.positions(List.of(new Rectangle(1f, 2f, 3f, 4f, 1)))
|
||||
.annotationId(entryToAddId)
|
||||
.value("Test")
|
||||
.reason("Reason")
|
||||
.addToDictionary(false)
|
||||
.addToDossierDictionary(false)
|
||||
.fileId(fileId)
|
||||
.requestDate(OffsetDateTime.now())
|
||||
.type("manual")
|
||||
.build()))
|
||||
.idsToRemove(Set.of(
|
||||
IdRemoval.builder()
|
||||
.annotationId(entryToRemoveId)
|
||||
.build()
|
||||
))
|
||||
.resizeRedactions(Set.of(
|
||||
ManualResizeRedaction.builder()
|
||||
.fileId(fileId)
|
||||
.value("Random")
|
||||
.annotationId(entryToResizeId)
|
||||
.positions(positions)
|
||||
.build()
|
||||
))
|
||||
.legalBasisChanges(Set.of(
|
||||
ManualLegalBasisChange.builder()
|
||||
.annotationId(entryLegalBasisId)
|
||||
.value("Random")
|
||||
.legalBasis("New legal basis")
|
||||
.section("Section")
|
||||
.build()
|
||||
))
|
||||
.forceRedactions(Set.of(
|
||||
ManualForceRedaction.builder()
|
||||
.annotationId(forceRedactionId)
|
||||
.fileId(fileId)
|
||||
.legalBasis("Force")
|
||||
.build()
|
||||
))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,5 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model;
|
||||
public enum MessageType {
|
||||
|
||||
ANALYSE,
|
||||
REANALYSE,
|
||||
SURROUNDING_TEXT
|
||||
REANALYSE
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<redaction-service.version>4.126.0</redaction-service.version>
|
||||
<redaction-service.version>4.157.0</redaction-service.version>
|
||||
<search-service.version>2.71.0</search-service.version>
|
||||
<pdftron-redaction-service.version>4.29.0</pdftron-redaction-service.version>
|
||||
<redaction-report-service.version>4.13.0</redaction-report-service.version>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user