RED-7838: merge numberOfComments into EntityLog #198

Merged
kilian.schuettler1 merged 1 commits from RED-7838 into master 2023-10-26 09:09:24 +02:00
8 changed files with 72 additions and 75 deletions

View File

@ -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<Comment> 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())

View File

@ -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);
}

View File

@ -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<Long> commentIds) {
public void deleteComment(String fileId, List<Long> commentIds) {
for (var commentId : commentIds) {
commentPersistenceService.softDelete(commentId, OffsetDateTime.now());
}
// update indicator
fileStatusPersistenceService.updateHasComments(fileId, commentPersistenceService.fileHasComments(fileId));
// 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<String, List<Comment>> 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<CommentEntity, Comment> 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<Comment> getComments(String fileId, String annotationId) {
return toCommentList(commentPersistenceService.findCommentsByAnnotationId(fileId, annotationId, false));
}
private static List<Comment> toCommentList(List<CommentEntity> entity) {
return entity.stream().map(CommentService::toComment).toList();
}
private static Comment toComment(CommentEntity entity) {
return MagicConverter.convert(entity, Comment.class, getDeltaMapper());
}
private static BiConsumer<CommentEntity, Comment> getDeltaMapper() {
return (c1, c2) -> c2.setUserId(c1.getUser());
}
public Map<String, Integer> getCommentCounts(String fileId) {
return commentPersistenceService.findCommentsByFileID(fileId, false).entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().size()));
}
}

View File

@ -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<String, Integer> commentCountPerAnnotationId = commentService.getCommentCounts(fileId);
entityLog.getEntityLogEntry().forEach(entityLogEntry -> entityLogEntry.setNumberOfComments(commentCountPerAnnotationId.getOrDefault(entityLogEntry.getId(), 0)));
return entityLog;
}

View File

@ -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;

View File

@ -11,7 +11,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.annotati
public interface CommentRepository extends JpaRepository<CommentEntity, Long> {
@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<CommentEntity> findByFileIdAndAnnotationId(String fileId, String annotationId, boolean includeDeletions);

View File

@ -35,7 +35,7 @@ public class EntityLogEntry {
List<Integer> containingNodeId;
String closestHeadline;
String section;
float[] color;
@Builder.Default
@ -71,4 +71,6 @@ public class EntityLogEntry {
@Builder.Default
Set<String> importedRedactionIntersections = new HashSet<>();
int numberOfComments;
}

View File

@ -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<String, List<Comment>> comments;
List<Comment> comments;
}