diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java index 2315ca208..0ffe9975e 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java @@ -28,8 +28,9 @@ import com.iqser.red.service.persistence.service.v1.api.external.resource.Manual import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationComments; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ForceRedactionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.LegalBasisChangeRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse; @@ -99,14 +100,15 @@ public class ManualRedactionController implements ManualRedactionResource { .message("Comment was removed.") .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) .build()); - commentService.deleteComment(dossierId, fileId, List.of(Long.valueOf(commentId))); + commentService.deleteComment(fileId, List.of(Long.valueOf(commentId))); } @Override @PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')") - public ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, + public ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed) { return manualRedactionService.getManualRedactions(fileId, unprocessed); @@ -115,12 +117,13 @@ public class ManualRedactionController implements ManualRedactionResource { @Override @PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')") - public Comments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { + public AnnotationComments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @PathVariable(ANNOTATION_ID) String annotationId) { dossierManagementService.getDossierById(dossierId, false, false); fileStatusManagementService.getFileStatus(fileId, false); - return commentService.getComments(fileId); + List comments = commentService.getComments(fileId, annotationId); + return new AnnotationComments(comments); } @@ -134,10 +137,7 @@ public class ManualRedactionController implements ManualRedactionResource { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId); - var response = commentService.addComment(dossierId, - fileId, - annotationId, - CommentRequest.builder().user(KeycloakSecurity.getUserId()).text(addCommentRequest.getText()).build()); + var response = commentService.addComment(fileId, annotationId, CommentRequest.builder().user(KeycloakSecurity.getUserId()).text(addCommentRequest.getText()).build()); auditPersistenceService.audit(AuditRequest.builder() .userId(KeycloakSecurity.getUserId()) diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java index 6ef93bec1..907d41ae8 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java @@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationComments; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequestModel; @@ -131,16 +131,17 @@ 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.") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) - ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed); + ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, + @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed); @ResponseStatus(value = HttpStatus.OK) - @GetMapping(value = MANUAL_REDACTION_REST_PATH + "/comments" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "Returns the comments for a specific file", description = "None") + @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")}) - Comments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId); + AnnotationComments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @PathVariable(ANNOTATION_ID) String annotationId); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java index aab36449d..f547f7335 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java @@ -17,7 +17,6 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.CommentPersistenceService; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; import lombok.AccessLevel; @@ -35,69 +34,34 @@ public class CommentService { @Transactional - public void deleteComment(String dossierId, String fileId, List commentIds) { + public void deleteComment(String fileId, List commentIds) { for (var commentId : commentIds) { commentPersistenceService.softDelete(commentId, OffsetDateTime.now()); } // update indicator fileStatusPersistenceService.updateHasComments(fileId, commentPersistenceService.fileHasComments(fileId)); - - // Since entityLog does not have comments, no need to trigger reprocess or to store them -// // This is an ugly workaround, don't even look at it! -// // Basically we should change how comments work and not merge them into the redaction log. -// // if file is currently not analyzing, we can quickly change the redaction log, else we must wait for the analysis to finish. -// if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { -// reprocess(dossierId, fileId); -// return; -// } -// fileStatusService.setStatusProcessing(fileId); -// RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); -// redactionLog.getRedactionLogEntry().forEach(entry -> entry.getComments().removeIf(comment -> commentIds.contains(comment.getId()))); -// fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); -// fileStatusService.setStatusProcessed(fileId); } @Transactional - public Comments getComments(String fileId) { + public Map> getComments(String fileId) { - return new Comments(commentPersistenceService.findCommentsByFileID(fileId, false) + return commentPersistenceService.findCommentsByFileID(fileId, false) .entrySet() .stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> MagicConverter.convert(entry.getValue(), Comment.class, getDeltaMapper())))); - } - - - private static BiConsumer getDeltaMapper() { - - return (c1, c2) -> c2.setUserId(c1.getUser()); + .collect(Collectors.toMap(Map.Entry::getKey, entry -> toCommentList(entry.getValue()))); } @Transactional - public CommentEntity addComment(String dossierId, String fileId, String annotationId, CommentRequest commentRequest) { + public CommentEntity addComment(String fileId, String annotationId, CommentRequest commentRequest) { checkComment(commentRequest.getText()); CommentEntity createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser()); fileStatusPersistenceService.updateHasComments(fileId, true); - // Since entityLog does not have comments, no need to trigger reprocess or to store them -// // This is an ugly workaround, don't even look at it! -// // Basically we should change how comments work and not merge them into the redaction log. -// if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { -// reprocess(dossierId, fileId); -// return createdComment; -// } -// fileStatusService.setStatusProcessing(fileId); -// RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); -// redactionLog.getRedactionLogEntry() -// .stream() -// .filter(entry -> entry.getId().equals(annotationId)) -// .forEach(entry -> entry.getComments().add(MagicConverter.convert(createdComment, RedactionLogComment.class))); -// fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); -// fileStatusService.setStatusProcessed(fileId); return createdComment; } @@ -141,10 +105,34 @@ public class CommentService { commentPersistenceService.hardDelete(fileId, annotationId); } -// -// private void reprocess(String dossierId, String fileId) { -// -// fileStatusService.setStatusReprocessForManual(dossierId, fileId, true); -// } + + public List getComments(String fileId, String annotationId) { + + return toCommentList(commentPersistenceService.findCommentsByAnnotationId(fileId, annotationId, false)); + } + + + private static List toCommentList(List entity) { + + return entity.stream().map(CommentService::toComment).toList(); + } + + + private static Comment toComment(CommentEntity entity) { + + return MagicConverter.convert(entity, Comment.class, getDeltaMapper()); + } + + + private static BiConsumer getDeltaMapper() { + + return (c1, c2) -> c2.setUserId(c1.getUser()); + } + + + public Map getCommentCounts(String fileId) { + + return commentPersistenceService.findCommentsByFileID(fileId, false).entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().size())); + } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java index 7a430f428..88bc4ebbd 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Map; import org.springframework.stereotype.Service; @@ -12,14 +13,18 @@ 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.FilteredEntityLogRequest; +import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; @Service @RequiredArgsConstructor +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class EntityLogService { - private final FileManagementStorageService fileManagementStorageService; - private final FileStatusService fileStatusService; + FileManagementStorageService fileManagementStorageService; + FileStatusService fileStatusService; + CommentService commentService; public EntityLog getEntityLog(String dossierId, String fileId) { @@ -32,19 +37,22 @@ public class EntityLogService { var fileStatus = fileStatusService.getStatus(fileId); - EntityLog redactionLog; + EntityLog entityLog; - redactionLog = fileManagementStorageService.getEntityLog(dossierId, fileId); + entityLog = fileManagementStorageService.getEntityLog(dossierId, fileId); if (fileStatus.isExcluded()) { - redactionLog.setEntityLogEntry(new ArrayList<>()); + entityLog.setEntityLogEntry(new ArrayList<>()); } if (excludedTypes != null) { - redactionLog.getEntityLogEntry().removeIf(entry -> excludedTypes.contains(entry.getType())); + entityLog.getEntityLogEntry().removeIf(entry -> excludedTypes.contains(entry.getType())); } - return redactionLog; + Map commentCountPerAnnotationId = commentService.getCommentCounts(fileId); + entityLog.getEntityLogEntry().forEach(entityLogEntry -> entityLogEntry.setNumberOfComments(commentCountPerAnnotationId.getOrDefault(entityLogEntry.getId(), 0))); + + return entityLog; } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java index 379c858d8..0c340a270 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java @@ -23,7 +23,6 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.management.v1.processor.utils.ManualImageRecategorizationMapper; import com.iqser.red.service.persistence.management.v1.processor.utils.ManualRedactionMapper; import com.iqser.red.service.persistence.management.v1.processor.utils.ManualResizeRedactionMapper; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.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; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java index 61bb92566..19f0f264b 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java @@ -11,7 +11,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.annotati public interface CommentRepository extends JpaRepository { - @Query("select e from CommentEntity e where e.fileId = :fileId and e.annotationId = :annotationId " + "and (:includeDeletions = true or e.softDeletedTime is null)") + @Query("select e from CommentEntity e where e.fileId = :fileId and e.annotationId = :annotationId and (:includeDeletions = true or e.softDeletedTime is null)") List findByFileIdAndAnnotationId(String fileId, String annotationId, boolean includeDeletions); diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntityLogEntry.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntityLogEntry.java index fc608f76a..b8105560c 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntityLogEntry.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntityLogEntry.java @@ -35,7 +35,7 @@ public class EntityLogEntry { List containingNodeId; String closestHeadline; String section; - + float[] color; @Builder.Default @@ -71,4 +71,6 @@ public class EntityLogEntry { @Builder.Default Set importedRedactionIntersections = new HashSet<>(); + int numberOfComments; + } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comments.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AnnotationComments.java similarity index 76% rename from persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comments.java rename to persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AnnotationComments.java index 07bce8c08..c4c308d99 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comments.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AnnotationComments.java @@ -1,7 +1,6 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations; import java.util.List; -import java.util.Map; import lombok.AllArgsConstructor; import lombok.Builder; @@ -12,8 +11,8 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class Comments { +public class AnnotationComments { - Map> comments; + List comments; }