Pull request #227: RED-3210 Approve all manual redactions if one is approved with the same value within the same file

Merge in RED/persistence-service from bugfix/RED-3210 to master

* commit '30cdd3d6cd4feecaa0414719dd6fbb9aa8864aea':
  RED-3210 Approve all manual redactions if one is approved with the same value
This commit is contained in:
Philipp Schramm 2022-02-14 13:57:15 +01:00 committed by Dominique Eiflaender
commit 9e763f194d
4 changed files with 201 additions and 104 deletions

View File

@ -1,5 +1,17 @@
package com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations; package com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.transaction.Transactional;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; 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.entity.annotations.RectangleEntity;
@ -8,27 +20,18 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist
import com.iqser.red.service.persistence.service.v1.api.model.annotations.AddRedactionRequest; import com.iqser.red.service.persistence.service.v1.api.model.annotations.AddRedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.model.annotations.AnnotationStatus;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.Rectangle; import com.iqser.red.service.persistence.service.v1.api.model.annotations.Rectangle;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional; import lombok.RequiredArgsConstructor;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class AddRedactionPersistenceService { public class AddRedactionPersistenceService {
private final ManualRedactionRepository manualRedactionRepository; private final ManualRedactionRepository manualRedactionRepository;
public ManualRedactionEntryEntity insert(String fileId, String annotationId, AddRedactionRequest addRedactionRequest) { public ManualRedactionEntryEntity insert(String fileId, String annotationId,
AddRedactionRequest addRedactionRequest) {
ManualRedactionEntryEntity manualRedactionEntry = new ManualRedactionEntryEntity(); ManualRedactionEntryEntity manualRedactionEntry = new ManualRedactionEntryEntity();
manualRedactionEntry.setId(new AnnotationEntityId(annotationId, fileId)); manualRedactionEntry.setId(new AnnotationEntityId(annotationId, fileId));
@ -41,7 +44,6 @@ public class AddRedactionPersistenceService {
manualRedactionEntry.setProcessedDate(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)); manualRedactionEntry.setProcessedDate(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
} }
return manualRedactionRepository.save(manualRedactionEntry); return manualRedactionRepository.save(manualRedactionEntry);
} }
@ -49,9 +51,11 @@ public class AddRedactionPersistenceService {
@Transactional @Transactional
public void updateSurroundingText(AnnotationEntityId id, String textBefore, String textAfter) { public void updateSurroundingText(AnnotationEntityId id, String textBefore, String textAfter) {
manualRedactionRepository.updateSurroundingText(id, textBefore, textAfter); manualRedactionRepository.updateSurroundingText(id, textBefore, textAfter);
} }
private List<RectangleEntity> convert(List<Rectangle> positions) { private List<RectangleEntity> convert(List<Rectangle> positions) {
List<RectangleEntity> rectangleEntities = new ArrayList<>(); List<RectangleEntity> rectangleEntities = new ArrayList<>();
@ -67,8 +71,7 @@ public class AddRedactionPersistenceService {
public ManualRedactionEntryEntity findAddRedaction(String fileId, String annotationId) { public ManualRedactionEntryEntity findAddRedaction(String fileId, String annotationId) {
return manualRedactionRepository.findAddRedaction(new AnnotationEntityId(annotationId, fileId)) return manualRedactionRepository.findAddRedaction(new AnnotationEntityId(annotationId, fileId))
.orElseThrow(() -> .orElseThrow(() -> new NotFoundException("Unknown file/annotation combination: " + fileId + "/" + annotationId));
new NotFoundException("Unknown file/annotation combination: " + fileId + "/" + annotationId));
} }
@ -81,17 +84,21 @@ public class AddRedactionPersistenceService {
@Transactional @Transactional
public void hardDelete(String fileId, String annotationId) { public void hardDelete(String fileId, String annotationId) {
manualRedactionRepository.deleteById(new AnnotationEntityId(annotationId, fileId)); manualRedactionRepository.deleteById(new AnnotationEntityId(annotationId, fileId));
} }
@Transactional @Transactional
public void softDelete(String fileId, String annotationId, OffsetDateTime softDeleteTime) { public void softDelete(String fileId, String annotationId, OffsetDateTime softDeleteTime) {
manualRedactionRepository.updateSoftDelete(new AnnotationEntityId(annotationId, fileId), softDeleteTime); manualRedactionRepository.updateSoftDelete(new AnnotationEntityId(annotationId, fileId), softDeleteTime);
} }
@Transactional @Transactional
public void undelete(String fileId, String annotationId) { public void undelete(String fileId, String annotationId) {
manualRedactionRepository.updateSoftDelete(new AnnotationEntityId(annotationId, fileId), null); manualRedactionRepository.updateSoftDelete(new AnnotationEntityId(annotationId, fileId), null);
} }
@ -102,10 +109,19 @@ public class AddRedactionPersistenceService {
manualRedactionRepository.updateStatus(new AnnotationEntityId(annotationId, fileId), annotationStatus); manualRedactionRepository.updateStatus(new AnnotationEntityId(annotationId, fileId), annotationStatus);
} }
@Transactional @Transactional
public void updateStatus(String fileId, String annotationId, AnnotationStatus annotationStatus, boolean isAddOrRemoveFromDictionary, boolean isAddOrRemoveFromDossierDictionary) { public void updateStatus(String fileId, String annotationId, AnnotationStatus annotationStatus,
boolean isAddOrRemoveFromDictionary, boolean isAddOrRemoveFromDossierDictionary) {
manualRedactionRepository.updateStatus(new AnnotationEntityId(annotationId, fileId), annotationStatus, isAddOrRemoveFromDictionary, isAddOrRemoveFromDossierDictionary); manualRedactionRepository.updateStatus(new AnnotationEntityId(annotationId, fileId), annotationStatus, isAddOrRemoveFromDictionary, isAddOrRemoveFromDossierDictionary);
} }
@Transactional
public void approveStatusForRequestedRedactionsWithSameValue(Set<String> fileIds, String value) {
manualRedactionRepository.updateStatus(fileIds, value, AnnotationStatus.REQUESTED, AnnotationStatus.APPROVED);
}
} }

View File

@ -1,41 +1,55 @@
package com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository; package com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.AnnotationStatus;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.AnnotationStatus;
public interface ManualRedactionRepository extends JpaRepository<ManualRedactionEntryEntity, AnnotationEntityId> { public interface ManualRedactionRepository extends JpaRepository<ManualRedactionEntryEntity, AnnotationEntityId> {
List<ManualRedactionEntryEntity> findByIdFileId(String fileId); List<ManualRedactionEntryEntity> findByIdFileId(String fileId);
@Modifying @Modifying
@Query("update ManualRedactionEntryEntity m set m.softDeletedTime = :softDeleteTime where m.id = :id") @Query("update ManualRedactionEntryEntity m set m.softDeletedTime = :softDeleteTime where m.id = :id")
void updateSoftDelete(AnnotationEntityId id, OffsetDateTime softDeleteTime); void updateSoftDelete(AnnotationEntityId id, OffsetDateTime softDeleteTime);
@Modifying @Modifying
@Query("update ManualRedactionEntryEntity m set m.status = :annotationStatus where m.id = :id") @Query("update ManualRedactionEntryEntity m set m.status = :annotationStatus where m.id = :id")
void updateStatus(AnnotationEntityId id, AnnotationStatus annotationStatus); void updateStatus(AnnotationEntityId id, AnnotationStatus annotationStatus);
@Modifying @Modifying
@Query("update ManualRedactionEntryEntity m set m.status = :annotationStatus," + @Query("update ManualRedactionEntryEntity m set m.status = :annotationStatus, m.addToDictionary = :isAddOrRemoveFromDictionary, m.addToDossierDictionary = :isAddOrRemoveFromDossierDictionary where m.id = :id")
" m.addToDictionary = :isAddOrRemoveFromDictionary, m.addToDossierDictionary = :isAddOrRemoveFromDossierDictionary where m.id = :id")
void updateStatus(AnnotationEntityId id, AnnotationStatus annotationStatus, boolean isAddOrRemoveFromDictionary, void updateStatus(AnnotationEntityId id, AnnotationStatus annotationStatus, boolean isAddOrRemoveFromDictionary,
boolean isAddOrRemoveFromDossierDictionary); boolean isAddOrRemoveFromDossierDictionary);
@Query("select m from ManualRedactionEntryEntity m where m.id = :id and m.softDeletedTime is null") @Query("select m from ManualRedactionEntryEntity m where m.id = :id and m.softDeletedTime is null")
Optional<ManualRedactionEntryEntity> findAddRedaction(AnnotationEntityId id); Optional<ManualRedactionEntryEntity> findAddRedaction(AnnotationEntityId id);
@Query("select m from ManualRedactionEntryEntity m where m.id.fileId = :fileId and (:includeDeletions = true or m.softDeletedTime is null)") @Query("select m from ManualRedactionEntryEntity m where m.id.fileId = :fileId and (:includeDeletions = true or m.softDeletedTime is null)")
List<ManualRedactionEntryEntity> findByFileIdIncludeDeletions(String fileId, boolean includeDeletions); List<ManualRedactionEntryEntity> findByFileIdIncludeDeletions(String fileId, boolean includeDeletions);
@Modifying @Modifying
@Query("update ManualRedactionEntryEntity m set m.textBefore = :textBefore, m.textAfter = :textAfter where m.id = :id") @Query("update ManualRedactionEntryEntity m set m.textBefore = :textBefore, m.textAfter = :textAfter where m.id = :id")
void updateSurroundingText(AnnotationEntityId id, String textBefore, String textAfter); void updateSurroundingText(AnnotationEntityId id, String textBefore, String textAfter);
@Modifying
@Query("update ManualRedactionEntryEntity m set m.status = :newStatus where m.id.fileId in :fileIds and m.value = :filterValue and m.addToDictionary = true and m.status = :filterStatus ")
void updateStatus(Set<String> fileIds, String filterValue, AnnotationStatus filterStatus,
AnnotationStatus newStatus);
} }

View File

@ -1,21 +1,22 @@
package com.iqser.red.service.peristence.v1.server.service; package com.iqser.red.service.peristence.v1.server.service;
import java.time.OffsetDateTime;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ViewedPageEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ViewedPageEntity;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ViewedPagesPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ViewedPagesPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.model.annotations.AnnotationStatus;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.WorkflowStatus; import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.WorkflowStatus;
import com.iqser.red.service.redaction.v1.model.ChangeType;
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry; import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.time.OffsetDateTime;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j @Slf4j
@Service @Service
@ -26,6 +27,7 @@ public class AnalysisFlagsCalculationService {
private final RedactionLogService redactionLogService; private final RedactionLogService redactionLogService;
private final ViewedPagesPersistenceService viewedPagesPersistenceService; private final ViewedPagesPersistenceService viewedPagesPersistenceService;
@Async @Async
public void calculateFlags(String dossierId, String fileId) { public void calculateFlags(String dossierId, String fileId) {
@ -36,7 +38,8 @@ public class AnalysisFlagsCalculationService {
var viewedPagesForCurrentAssignee = viewedPagesPersistenceService.findViewedPages(fileId, file.getAssignee()); var viewedPagesForCurrentAssignee = viewedPagesPersistenceService.findViewedPages(fileId, file.getAssignee());
Map<Integer, OffsetDateTime> viewedPages = viewedPagesForCurrentAssignee.stream().collect(Collectors.toMap(ViewedPageEntity::getPage, ViewedPageEntity::getViewedTime)); Map<Integer, OffsetDateTime> viewedPages = viewedPagesForCurrentAssignee.stream()
.collect(Collectors.toMap(ViewedPageEntity::getPage, ViewedPageEntity::getViewedTime));
boolean hasRedactions = false; boolean hasRedactions = false;
boolean hasHints = false; boolean hasHints = false;
@ -54,6 +57,14 @@ public class AnalysisFlagsCalculationService {
String type = getType(entry.getType()); String type = getType(entry.getType());
var lastChange = entry.getChanges().isEmpty() ? null : entry.getChanges()
.get(entry.getChanges().size() - 1);
if (lastChange != null && (lastModification == null || lastChange.getDateTime()
.isAfter(lastModification))) {
lastModification = lastChange.getDateTime();
}
if (!hasRedactions && entry.isRedacted()) { if (!hasRedactions && entry.isRedacted()) {
hasRedactions = true; hasRedactions = true;
} }
@ -66,7 +77,9 @@ public class AnalysisFlagsCalculationService {
hasImages = true; hasImages = true;
} }
if (!hasSuggestions && entry.getManualChanges().stream().anyMatch(e -> e.getAnnotationStatus() == AnnotationStatus.REQUESTED)) { if (!hasSuggestions && lastChange != null && lastChange.getType() != ChangeType.REMOVED && entry.getManualChanges()
.stream()
.anyMatch(e -> e.getAnnotationStatus() == AnnotationStatus.REQUESTED)) {
hasSuggestions = true; hasSuggestions = true;
} }
@ -74,13 +87,9 @@ public class AnalysisFlagsCalculationService {
hasComments = true; hasComments = true;
} }
var lastChange = entry.getChanges().isEmpty() ? null : entry.getChanges().get(entry.getChanges().size() - 1); var viewedPage = entry.getPositions().isEmpty() ? null : viewedPages.get(entry.getPositions()
.get(0)
if(lastChange != null && (lastModification == null || lastChange.getDateTime().isAfter(lastModification))){ .getPage());
lastModification = lastChange.getDateTime();
}
var viewedPage = entry.getPositions().isEmpty() ? null : viewedPages.get(entry.getPositions().get(0).getPage());
if (file.getWorkflowStatus() != WorkflowStatus.APPROVED && lastChange != null && lastChange.getDateTime() != null && viewedPage != null && viewedPage.isBefore(lastChange.getDateTime())) { if (file.getWorkflowStatus() != WorkflowStatus.APPROVED && lastChange != null && lastChange.getDateTime() != null && viewedPage != null && viewedPage.isBefore(lastChange.getDateTime())) {
hasUpdates = true; hasUpdates = true;
@ -88,15 +97,9 @@ public class AnalysisFlagsCalculationService {
} }
log.info("Flag Calculations for file: {} took: {}ms", fileId, System.currentTimeMillis() - startTime); log.info("Flag Calculations for file: {} took: {}ms", fileId, System.currentTimeMillis() - startTime);
if (file.isHasRedactions() == hasRedactions && if (file.isHasRedactions() == hasRedactions && file.isHasHints() == hasHints && file.isHasImages() == hasImages && file.isHasSuggestions() == hasSuggestions && file.isHasAnnotationComments() == hasComments && file.isHasUpdates() == hasUpdates) {
file.isHasHints() == hasHints &&
file.isHasImages() == hasImages &&
file.isHasSuggestions() == hasSuggestions &&
file.isHasAnnotationComments() == hasComments &&
file.isHasUpdates() == hasUpdates) {
log.info("Nothing Changed for file: {}", fileId); log.info("Nothing Changed for file: {}", fileId);
} else { } else {
fileStatusPersistenceService.updateFlags(fileId, hasRedactions, hasHints, hasImages, hasSuggestions, hasComments, hasUpdates); fileStatusPersistenceService.updateFlags(fileId, hasRedactions, hasHints, hasImages, hasSuggestions, hasComments, hasUpdates);
@ -107,18 +110,16 @@ public class AnalysisFlagsCalculationService {
lastModification = lastManualRedactionTime; lastModification = lastManualRedactionTime;
} }
if(lastModification != null && (file.getAnnotationModificationDate() == null || file.getAnnotationModificationDate().isBefore(lastModification))) { if (lastModification != null && (file.getAnnotationModificationDate() == null || file.getAnnotationModificationDate()
.isBefore(lastModification))) {
fileStatusPersistenceService.setLastAnnotationModificationDateForFile(fileId, lastModification); fileStatusPersistenceService.setLastAnnotationModificationDateForFile(fileId, lastModification);
} }
} }
private String getType(String typeId) { private String getType(String typeId) {
return typeId.split(":")[0]; return typeId.split(":")[0];
} }
} }

View File

@ -1,5 +1,22 @@
package com.iqser.red.service.peristence.v1.server.service; package com.iqser.red.service.peristence.v1.server.service;
import static com.iqser.red.service.persistence.management.v1.processor.utils.MagicConverter.convert;
import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId;
import java.nio.charset.StandardCharsets;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.transaction.Transactional;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.hash.HashFunction; import com.google.common.hash.HashFunction;
@ -8,15 +25,38 @@ import com.iqser.red.service.peristence.v1.server.configuration.MessagingConfigu
import com.iqser.red.service.peristence.v1.server.controller.DictionaryController; import com.iqser.red.service.peristence.v1.server.controller.DictionaryController;
import com.iqser.red.service.peristence.v1.server.utils.ManualRedactionMapper; import com.iqser.red.service.peristence.v1.server.utils.ManualRedactionMapper;
import com.iqser.red.service.peristence.v1.server.utils.ManualResizeRedactionMapper; import com.iqser.red.service.peristence.v1.server.utils.ManualResizeRedactionMapper;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.*; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.CommentEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualForceRedactionEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualImageRecategorizationEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualLegalBasisChangeEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualResizeRedactionEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException; import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.*; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.*; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.CommentPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ForceRedactionPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ImageRecategorizationPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.LegalBasisChangePersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.AddRedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.AnnotationStatus;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.CommentRequest;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ForceRedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ImageRecategorizationRequest;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.LegalBasisChangeRequest;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ManualAddResponse;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ManualRedactions;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.RemoveRedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ResizeRedactionRequest;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.entitymapped.ManualRedactionEntry; import com.iqser.red.service.persistence.service.v1.api.model.annotations.entitymapped.ManualRedactionEntry;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.entitymapped.ManualResizeRedaction; import com.iqser.red.service.persistence.service.v1.api.model.annotations.entitymapped.ManualResizeRedaction;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.ProcessingStatus; import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.ProcessingStatus;
@ -24,22 +64,10 @@ import com.iqser.red.service.redaction.v1.model.AnalyzeRequest;
import com.iqser.red.service.redaction.v1.model.MessageType; import com.iqser.red.service.redaction.v1.model.MessageType;
import com.iqser.red.service.redaction.v1.model.RedactionLog; import com.iqser.red.service.redaction.v1.model.RedactionLog;
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry; import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
import feign.FeignException; import feign.FeignException;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.nio.charset.StandardCharsets;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import static com.iqser.red.service.persistence.management.v1.processor.utils.MagicConverter.convert;
import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId;
@Slf4j @Slf4j
@Service @Service
@ -47,6 +75,7 @@ import static com.iqser.red.service.persistence.management.v1.processor.utils.Ty
public class ManualRedactionService { public class ManualRedactionService {
private final DossierPersistenceService dossierPersistenceService; private final DossierPersistenceService dossierPersistenceService;
private final DossierTemplatePersistenceService dossierTemplatePersistenceService;
private final AddRedactionPersistenceService addRedactionPersistenceService; private final AddRedactionPersistenceService addRedactionPersistenceService;
private final RemoveRedactionPersistenceService removeRedactionPersistenceService; private final RemoveRedactionPersistenceService removeRedactionPersistenceService;
private final ForceRedactionPersistenceService forceRedactionPersistenceService; private final ForceRedactionPersistenceService forceRedactionPersistenceService;
@ -114,6 +143,7 @@ public class ManualRedactionService {
return ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).build(); return ManualAddResponse.builder().annotationId(annotationId).commentId(commentId).build();
} }
public ManualAddResponse addRemoveRedaction(String dossierId, String fileId, public ManualAddResponse addRemoveRedaction(String dossierId, String fileId,
RemoveRedactionRequest removeRedactionRequest) { RemoveRedactionRequest removeRedactionRequest) {
@ -275,6 +305,7 @@ public class ManualRedactionService {
.build(); .build();
} }
public CommentEntity addComment(String fileId, String annotationId, CommentRequest commentRequest) { public CommentEntity addComment(String fileId, String annotationId, CommentRequest commentRequest) {
var createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser()); var createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser());
@ -466,6 +497,8 @@ public class ManualRedactionService {
if (annotationStatus == AnnotationStatus.APPROVED) { if (annotationStatus == AnnotationStatus.APPROVED) {
removeFromDictionary(buildTypeId(redactionLogEntry, dossier), redactionLogEntry.getValue(), dossierId, fileId); removeFromDictionary(buildTypeId(redactionLogEntry, dossier), redactionLogEntry.getValue(), dossierId, fileId);
approveStatusForRedactionsWithSameValue(dossier, false, true, redactionLogEntry.getValue());
} else if (annotationStatus == AnnotationStatus.DECLINED) { } else if (annotationStatus == AnnotationStatus.DECLINED) {
// if it was previously approved, revert the delete // if it was previously approved, revert the delete
@ -530,33 +563,6 @@ public class ManualRedactionService {
} }
@SuppressWarnings("PMD")
public void updateAddRedactionStatus(String dossierId, String fileId, String annotationId,
AnnotationStatus annotationStatus) {
dossierPersistenceService.getAndValidateDossier(dossierId);
ManualRedactionEntryEntity manualRedactionEntry = addRedactionPersistenceService.findAddRedaction(fileId, annotationId);
if (manualRedactionEntry.isAddToDictionary() || manualRedactionEntry.isAddToDossierDictionary()) {
if (annotationStatus == AnnotationStatus.APPROVED) {
addToDictionary(manualRedactionEntry.getTypeId(), manualRedactionEntry.getValue(), dossierId, fileId);
} else if (annotationStatus == AnnotationStatus.DECLINED) {
// if it was previously approved, revert the add
if (manualRedactionEntry.getStatus() == AnnotationStatus.APPROVED) {
removeFromDictionary(manualRedactionEntry.getTypeId(), manualRedactionEntry.getValue(), dossierId, fileId);
}
}
}
addRedactionPersistenceService.updateStatus(fileId, annotationId, annotationStatus);
boolean hasSuggestions = calculateHasSuggestions(fileId);
fileStatusPersistenceService.setUpdateLastManualRedactionAndHasSuggestions(fileId, OffsetDateTime.now(), hasSuggestions);
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
}
public void updateResizeRedactionStatus(String dossierId, String fileId, String annotationId, public void updateResizeRedactionStatus(String dossierId, String fileId, String annotationId,
AnnotationStatus annotationStatus) { AnnotationStatus annotationStatus) {
@ -574,12 +580,33 @@ public class ManualRedactionService {
} }
@Transactional @SuppressWarnings("PMD")
public void updateSurroundingText(String fileId, ManualRedactions manualRedactions) { public void updateAddRedactionStatus(String dossierId, String fileId, String annotationId,
AnnotationStatus annotationStatus) {
// These are marked as processed once surrounding text is computed ( TBD if this is correct ? ) var dossier = dossierPersistenceService.getAndValidateDossier(dossierId);
manualRedactions.getEntriesToAdd().forEach(e -> addRedactionPersistenceService.updateSurroundingText(new AnnotationEntityId(e.getAnnotationId(), fileId), e.getTextBefore(), e.getTextAfter()));
manualRedactions.getResizeRedactions().forEach(e -> resizeRedactionPersistenceService.updateSurroundingText(new AnnotationEntityId(e.getAnnotationId(), fileId), e.getTextBefore(), e.getTextAfter())); ManualRedactionEntryEntity manualRedactionEntry = addRedactionPersistenceService.findAddRedaction(fileId, annotationId);
if (manualRedactionEntry.isAddToDictionary() || manualRedactionEntry.isAddToDossierDictionary()) {
if (annotationStatus == AnnotationStatus.APPROVED) {
addToDictionary(manualRedactionEntry.getTypeId(), manualRedactionEntry.getValue(), dossierId, fileId);
approveStatusForRedactionsWithSameValue(dossier, manualRedactionEntry.isAddToDictionary(), manualRedactionEntry.isAddToDossierDictionary(), manualRedactionEntry.getValue());
} else if (annotationStatus == AnnotationStatus.DECLINED) {
// if it was previously approved, revert the add
if (manualRedactionEntry.getStatus() == AnnotationStatus.APPROVED) {
removeFromDictionary(manualRedactionEntry.getTypeId(), manualRedactionEntry.getValue(), dossierId, fileId);
}
}
}
addRedactionPersistenceService.updateStatus(fileId, annotationId, annotationStatus);
boolean hasSuggestions = calculateHasSuggestions(fileId);
fileStatusPersistenceService.setUpdateLastManualRedactionAndHasSuggestions(fileId, OffsetDateTime.now(), hasSuggestions);
analysisFlagsCalculationService.calculateFlags(dossierId, fileId);
} }
@ -594,7 +621,19 @@ public class ManualRedactionService {
} }
@Transactional
public void updateSurroundingText(String fileId, ManualRedactions manualRedactions) {
// These are marked as processed once surrounding text is computed ( TBD if this is correct ? )
manualRedactions.getEntriesToAdd()
.forEach(e -> addRedactionPersistenceService.updateSurroundingText(new AnnotationEntityId(e.getAnnotationId(), fileId), e.getTextBefore(), e.getTextAfter()));
manualRedactions.getResizeRedactions()
.forEach(e -> resizeRedactionPersistenceService.updateSurroundingText(new AnnotationEntityId(e.getAnnotationId(), fileId), e.getTextBefore(), e.getTextAfter()));
}
private void reprocess(String dossierId, String fileId) { private void reprocess(String dossierId, String fileId) {
fileStatusService.setStatusReprocess(dossierId, fileId, 2); fileStatusService.setStatusReprocess(dossierId, fileId, 2);
} }
@ -608,6 +647,7 @@ public class ManualRedactionService {
} }
} }
private void handleAddToDictionary(String fileId, String annotationId, String typeId, String value, private void handleAddToDictionary(String fileId, String annotationId, String typeId, String value,
AnnotationStatus status, boolean addToDictionary, boolean addToDossierDictionary, AnnotationStatus status, boolean addToDictionary, boolean addToDossierDictionary,
boolean revert, String dossierId) { boolean revert, String dossierId) {
@ -760,4 +800,30 @@ public class ManualRedactionService {
} }
private void approveStatusForRedactionsWithSameValue(DossierEntity dossier, boolean addToDictionary,
boolean addToDossierDictionary, String value) {
List<DossierEntity> dossiers = new ArrayList<>();
if (addToDictionary) {
dossiers = dossierTemplatePersistenceService.getDossierTemplate(dossier.getDossierTemplateId())
.getDossiers();
}
if (addToDossierDictionary) {
dossiers.add(dossier);
}
Set<String> fileIds = new HashSet<>();
for (DossierEntity d : dossiers) {
var files = fileStatusService.getDossierStatus(d.getId());
files.forEach(f -> fileIds.add(f.getId()));
}
if (!fileIds.isEmpty()) {
log.debug("Approve status for requested redactions with same value '{}' for files {}", value, fileIds);
addRedactionPersistenceService.approveStatusForRequestedRedactionsWithSameValue(fileIds, value);
}
}
} }