refactor(comment): drop dead document and annotation comment APIs
Only block comments are surfaced by the frontend now. The document-level and annotation-level comment endpoints and service methods existed but had no consumer. Remove them along with their repository queries and test coverage so the surface area matches the actual feature set. Shared edit, delete, and block reply endpoints stay. postBlockComment now carries the authorName/mention/audit behaviors previously tested through the dropped postComment method, so those behaviors remain covered by the block-scoped test suite. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,67 +24,6 @@ public class CommentController {
|
||||
private final CommentService commentService;
|
||||
private final UserService userService;
|
||||
|
||||
// ─── General document comments ────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/api/documents/{documentId}/comments")
|
||||
public List<DocumentComment> getDocumentComments(@PathVariable UUID documentId) {
|
||||
return commentService.getCommentsForDocument(documentId);
|
||||
}
|
||||
|
||||
@PostMapping("/api/documents/{documentId}/comments")
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@RequirePermission({Permission.ANNOTATE_ALL, Permission.WRITE_ALL})
|
||||
public DocumentComment postDocumentComment(
|
||||
@PathVariable UUID documentId,
|
||||
@RequestBody CreateCommentDTO dto,
|
||||
Authentication authentication) {
|
||||
AppUser author = resolveUser(authentication);
|
||||
return commentService.postComment(documentId, null, dto.getContent(), dto.getMentionedUserIds(), author);
|
||||
}
|
||||
|
||||
@PostMapping("/api/documents/{documentId}/comments/{commentId}/replies")
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@RequirePermission({Permission.ANNOTATE_ALL, Permission.WRITE_ALL})
|
||||
public DocumentComment replyToDocumentComment(
|
||||
@PathVariable UUID documentId,
|
||||
@PathVariable UUID commentId,
|
||||
@RequestBody CreateCommentDTO dto,
|
||||
Authentication authentication) {
|
||||
AppUser author = resolveUser(authentication);
|
||||
return commentService.replyToComment(documentId, commentId, dto.getContent(), dto.getMentionedUserIds(), author);
|
||||
}
|
||||
|
||||
// ─── Annotation comments ──────────────────────────────────────────────────
|
||||
|
||||
@GetMapping("/api/documents/{documentId}/annotations/{annotationId}/comments")
|
||||
public List<DocumentComment> getAnnotationComments(@PathVariable UUID annotationId) {
|
||||
return commentService.getCommentsForAnnotation(annotationId);
|
||||
}
|
||||
|
||||
@PostMapping("/api/documents/{documentId}/annotations/{annotationId}/comments")
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@RequirePermission({Permission.ANNOTATE_ALL, Permission.WRITE_ALL})
|
||||
public DocumentComment postAnnotationComment(
|
||||
@PathVariable UUID documentId,
|
||||
@PathVariable UUID annotationId,
|
||||
@RequestBody CreateCommentDTO dto,
|
||||
Authentication authentication) {
|
||||
AppUser author = resolveUser(authentication);
|
||||
return commentService.postComment(documentId, annotationId, dto.getContent(), dto.getMentionedUserIds(), author);
|
||||
}
|
||||
|
||||
@PostMapping("/api/documents/{documentId}/annotations/{annotationId}/comments/{commentId}/replies")
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@RequirePermission({Permission.ANNOTATE_ALL, Permission.WRITE_ALL})
|
||||
public DocumentComment replyToAnnotationComment(
|
||||
@PathVariable UUID documentId,
|
||||
@PathVariable UUID commentId,
|
||||
@RequestBody CreateCommentDTO dto,
|
||||
Authentication authentication) {
|
||||
AppUser author = resolveUser(authentication);
|
||||
return commentService.replyToComment(documentId, commentId, dto.getContent(), dto.getMentionedUserIds(), author);
|
||||
}
|
||||
|
||||
// ─── Block (transcription) comments ────────────────────────────────────────
|
||||
|
||||
@GetMapping("/api/documents/{documentId}/transcription-blocks/{blockId}/comments")
|
||||
|
||||
@@ -8,10 +8,6 @@ import java.util.UUID;
|
||||
|
||||
public interface CommentRepository extends JpaRepository<DocumentComment, UUID> {
|
||||
|
||||
List<DocumentComment> findByDocumentIdAndAnnotationIdIsNullAndParentIdIsNull(UUID documentId);
|
||||
|
||||
List<DocumentComment> findByAnnotationIdAndParentIdIsNull(UUID annotationId);
|
||||
|
||||
List<DocumentComment> findByParentId(UUID parentId);
|
||||
|
||||
List<DocumentComment> findByBlockIdAndParentIdIsNull(UUID blockId);
|
||||
|
||||
@@ -29,17 +29,6 @@ public class CommentService {
|
||||
private final AuditService auditService;
|
||||
private final TranscriptionService transcriptionService;
|
||||
|
||||
public List<DocumentComment> getCommentsForDocument(UUID documentId) {
|
||||
List<DocumentComment> roots =
|
||||
commentRepository.findByDocumentIdAndAnnotationIdIsNullAndParentIdIsNull(documentId);
|
||||
return withRepliesAndMentions(roots);
|
||||
}
|
||||
|
||||
public List<DocumentComment> getCommentsForAnnotation(UUID annotationId) {
|
||||
List<DocumentComment> roots = commentRepository.findByAnnotationIdAndParentIdIsNull(annotationId);
|
||||
return withRepliesAndMentions(roots);
|
||||
}
|
||||
|
||||
public List<DocumentComment> getCommentsForBlock(UUID blockId) {
|
||||
List<DocumentComment> roots = commentRepository.findByBlockIdAndParentIdIsNull(blockId);
|
||||
return withRepliesAndMentions(roots);
|
||||
@@ -65,24 +54,6 @@ public class CommentService {
|
||||
return saved;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public DocumentComment postComment(UUID documentId, UUID annotationId, String content,
|
||||
List<UUID> mentionedUserIds, AppUser author) {
|
||||
DocumentComment comment = DocumentComment.builder()
|
||||
.documentId(documentId)
|
||||
.annotationId(annotationId)
|
||||
.content(content)
|
||||
.authorId(author.getId())
|
||||
.authorName(resolveAuthorName(author))
|
||||
.build();
|
||||
saveMentions(comment, mentionedUserIds);
|
||||
DocumentComment saved = commentRepository.save(comment);
|
||||
withMentionDTOs(saved);
|
||||
notificationService.notifyMentions(mentionedUserIds, saved);
|
||||
logCommentPosted(author, documentId, saved, mentionedUserIds);
|
||||
return saved;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public DocumentComment replyToComment(UUID documentId, UUID commentId, String content,
|
||||
List<UUID> mentionedUserIds, AppUser author) {
|
||||
|
||||
@@ -40,246 +40,8 @@ class CommentControllerTest {
|
||||
|
||||
private static final String COMMENT_JSON = "{\"content\":\"Test comment\"}";
|
||||
private static final UUID DOC_ID = UUID.randomUUID();
|
||||
private static final UUID ANN_ID = UUID.randomUUID();
|
||||
private static final UUID COMMENT_ID = UUID.randomUUID();
|
||||
|
||||
// ─── GET /api/documents/{documentId}/comments ─────────────────────────────
|
||||
|
||||
@Test
|
||||
void getDocumentComments_returns401_whenUnauthenticated() throws Exception {
|
||||
mockMvc.perform(get("/api/documents/" + DOC_ID + "/comments"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void getDocumentComments_returns200_whenAuthenticated() throws Exception {
|
||||
when(commentService.getCommentsForDocument(any())).thenReturn(List.of());
|
||||
mockMvc.perform(get("/api/documents/" + DOC_ID + "/comments"))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
// ─── POST /api/documents/{documentId}/comments ────────────────────────────
|
||||
|
||||
@Test
|
||||
void postDocumentComment_returns401_whenUnauthenticated() throws Exception {
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void postDocumentComment_returns403_whenMissingPermission() throws Exception {
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ANNOTATE_ALL")
|
||||
void postDocumentComment_returns201_whenHasPermission() throws Exception {
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(COMMENT_ID).documentId(DOC_ID).authorName("Hans").content("Test comment").build();
|
||||
when(commentService.postComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.content").value("Test comment"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "WRITE_ALL")
|
||||
void postDocumentComment_returns201_whenHasWriteAllPermission() throws Exception {
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(COMMENT_ID).documentId(DOC_ID).authorName("Hans").content("Test comment").build();
|
||||
when(commentService.postComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
// ─── POST /api/documents/{documentId}/comments/{commentId}/replies ────────
|
||||
|
||||
@Test
|
||||
void replyToComment_returns401_whenUnauthenticated() throws Exception {
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID + "/replies")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ANNOTATE_ALL")
|
||||
void replyToComment_returns201_whenHasPermission() throws Exception {
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(DOC_ID).parentId(COMMENT_ID)
|
||||
.authorName("Anna").content("Test comment").build();
|
||||
when(commentService.replyToComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID + "/replies")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "WRITE_ALL")
|
||||
void replyToComment_returns201_whenHasWriteAllPermission() throws Exception {
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(DOC_ID).parentId(COMMENT_ID)
|
||||
.authorName("Anna").content("Test comment").build();
|
||||
when(commentService.replyToComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID + "/replies")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
// ─── PATCH /api/documents/{documentId}/comments/{commentId} ──────────────
|
||||
|
||||
@Test
|
||||
void editComment_returns401_whenUnauthenticated() throws Exception {
|
||||
mockMvc.perform(patch("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID)
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ANNOTATE_ALL")
|
||||
void editComment_returns200_whenHasPermission() throws Exception {
|
||||
DocumentComment updated = DocumentComment.builder()
|
||||
.id(COMMENT_ID).documentId(DOC_ID).authorName("Hans").content("Test comment").build();
|
||||
when(commentService.editComment(any(), any(), any(), any())).thenReturn(updated);
|
||||
|
||||
mockMvc.perform(patch("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID)
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
// ─── DELETE /api/documents/{documentId}/comments/{commentId} ─────────────
|
||||
|
||||
@Test
|
||||
void deleteComment_returns401_whenUnauthenticated() throws Exception {
|
||||
mockMvc.perform(delete("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void deleteComment_returns204_whenAuthenticated() throws Exception {
|
||||
mockMvc.perform(delete("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID))
|
||||
.andExpect(status().isNoContent());
|
||||
}
|
||||
|
||||
// ─── GET /api/documents/{documentId}/annotations/{annId}/comments ─────────
|
||||
|
||||
@Test
|
||||
void getAnnotationComments_returns401_whenUnauthenticated() throws Exception {
|
||||
mockMvc.perform(get("/api/documents/" + DOC_ID + "/annotations/" + ANN_ID + "/comments"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void getAnnotationComments_returns200_whenAuthenticated() throws Exception {
|
||||
when(commentService.getCommentsForAnnotation(any())).thenReturn(List.of());
|
||||
mockMvc.perform(get("/api/documents/" + DOC_ID + "/annotations/" + ANN_ID + "/comments"))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "WRITE_ALL")
|
||||
void editComment_returns200_whenHasWriteAllPermission() throws Exception {
|
||||
DocumentComment updated = DocumentComment.builder()
|
||||
.id(COMMENT_ID).documentId(DOC_ID).authorName("Hans").content("Test comment").build();
|
||||
when(commentService.editComment(any(), any(), any(), any())).thenReturn(updated);
|
||||
|
||||
mockMvc.perform(patch("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID)
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
// ─── POST /api/documents/{documentId}/annotations/{annId}/comments ────────
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void postAnnotationComment_returns403_whenMissingPermission() throws Exception {
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/annotations/" + ANN_ID + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ANNOTATE_ALL")
|
||||
void postAnnotationComment_returns201_whenHasPermission() throws Exception {
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(DOC_ID).annotationId(ANN_ID)
|
||||
.authorName("Hans").content("Test comment").build();
|
||||
when(commentService.postComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/annotations/" + ANN_ID + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "WRITE_ALL")
|
||||
void postAnnotationComment_returns201_whenHasWriteAllPermission() throws Exception {
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(DOC_ID).annotationId(ANN_ID)
|
||||
.authorName("Hans").content("Test comment").build();
|
||||
when(commentService.postComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/annotations/" + ANN_ID + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
// ─── POST /api/documents/{documentId}/annotations/{annId}/comments/{commentId}/replies ─
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ANNOTATE_ALL")
|
||||
void replyToAnnotationComment_returns201_whenHasPermission() throws Exception {
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(DOC_ID).annotationId(ANN_ID)
|
||||
.parentId(COMMENT_ID).authorName("Anna").content("Test comment").build();
|
||||
when(commentService.replyToComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/annotations/" + ANN_ID + "/comments/" + COMMENT_ID + "/replies")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "WRITE_ALL")
|
||||
void replyToAnnotationComment_returns201_whenHasWriteAllPermission() throws Exception {
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(DOC_ID).annotationId(ANN_ID)
|
||||
.parentId(COMMENT_ID).authorName("Anna").content("Test comment").build();
|
||||
when(commentService.replyToComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/annotations/" + ANN_ID + "/comments/" + COMMENT_ID + "/replies")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
// ─── resolveUser — exception branch ──────────────────────────────────────
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "WRITE_ALL")
|
||||
void postDocumentComment_stillSucceeds_whenUserServiceThrows() throws Exception {
|
||||
// findByEmail throws → catch block in resolveUser → author null, saves anyway
|
||||
when(userService.findByEmail(any())).thenThrow(new RuntimeException("DB error"));
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(DOC_ID).content("Test comment").build();
|
||||
when(commentService.postComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
// ─── Block comment endpoints ─────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
@@ -305,4 +67,138 @@ class CommentControllerTest {
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.blockId").value(blockId.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void postBlockComment_returns401_whenUnauthenticated() throws Exception {
|
||||
UUID blockId = UUID.randomUUID();
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/transcription-blocks/" + blockId + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void postBlockComment_returns403_whenMissingPermission() throws Exception {
|
||||
UUID blockId = UUID.randomUUID();
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/transcription-blocks/" + blockId + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ANNOTATE_ALL")
|
||||
void postBlockComment_returns201_whenHasAnnotatePermission() throws Exception {
|
||||
UUID blockId = UUID.randomUUID();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(DOC_ID).blockId(blockId).content("Nice").build();
|
||||
when(commentService.postBlockComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/transcription-blocks/" + blockId + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "WRITE_ALL")
|
||||
void postBlockComment_stillSucceeds_whenUserServiceThrows() throws Exception {
|
||||
// findByEmail throws → catch block in resolveUser → author null, saves anyway
|
||||
UUID blockId = UUID.randomUUID();
|
||||
when(userService.findByEmail(any())).thenThrow(new RuntimeException("DB error"));
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(DOC_ID).blockId(blockId).content("Test comment").build();
|
||||
when(commentService.postBlockComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/transcription-blocks/" + blockId + "/comments")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
// ─── Block reply endpoints ───────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void replyToBlockComment_returns401_whenUnauthenticated() throws Exception {
|
||||
UUID blockId = UUID.randomUUID();
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/transcription-blocks/" + blockId
|
||||
+ "/comments/" + COMMENT_ID + "/replies")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ANNOTATE_ALL")
|
||||
void replyToBlockComment_returns201_whenHasPermission() throws Exception {
|
||||
UUID blockId = UUID.randomUUID();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(DOC_ID).blockId(blockId).parentId(COMMENT_ID)
|
||||
.authorName("Anna").content("Reply").build();
|
||||
when(commentService.replyToComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/transcription-blocks/" + blockId
|
||||
+ "/comments/" + COMMENT_ID + "/replies")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "WRITE_ALL")
|
||||
void replyToBlockComment_returns201_whenHasWriteAllPermission() throws Exception {
|
||||
UUID blockId = UUID.randomUUID();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(DOC_ID).blockId(blockId).parentId(COMMENT_ID)
|
||||
.authorName("Anna").content("Reply").build();
|
||||
when(commentService.replyToComment(any(), any(), any(), any(), any())).thenReturn(saved);
|
||||
|
||||
mockMvc.perform(post("/api/documents/" + DOC_ID + "/transcription-blocks/" + blockId
|
||||
+ "/comments/" + COMMENT_ID + "/replies")
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isCreated());
|
||||
}
|
||||
|
||||
// ─── PATCH /api/documents/{documentId}/comments/{commentId} (shared edit) ──
|
||||
|
||||
@Test
|
||||
void editComment_returns401_whenUnauthenticated() throws Exception {
|
||||
mockMvc.perform(patch("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID)
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ANNOTATE_ALL")
|
||||
void editComment_returns200_whenHasPermission() throws Exception {
|
||||
DocumentComment updated = DocumentComment.builder()
|
||||
.id(COMMENT_ID).documentId(DOC_ID).authorName("Hans").content("Test comment").build();
|
||||
when(commentService.editComment(any(), any(), any(), any())).thenReturn(updated);
|
||||
|
||||
mockMvc.perform(patch("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID)
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "WRITE_ALL")
|
||||
void editComment_returns200_whenHasWriteAllPermission() throws Exception {
|
||||
DocumentComment updated = DocumentComment.builder()
|
||||
.id(COMMENT_ID).documentId(DOC_ID).authorName("Hans").content("Test comment").build();
|
||||
when(commentService.editComment(any(), any(), any(), any())).thenReturn(updated);
|
||||
|
||||
mockMvc.perform(patch("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID)
|
||||
.contentType(MediaType.APPLICATION_JSON).content(COMMENT_JSON))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
// ─── DELETE /api/documents/{documentId}/comments/{commentId} (shared) ────
|
||||
|
||||
@Test
|
||||
void deleteComment_returns401_whenUnauthenticated() throws Exception {
|
||||
mockMvc.perform(delete("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void deleteComment_returns204_whenAuthenticated() throws Exception {
|
||||
mockMvc.perform(delete("/api/documents/" + DOC_ID + "/comments/" + COMMENT_ID))
|
||||
.andExpect(status().isNoContent());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,52 +43,6 @@ class CommentServiceTest {
|
||||
@Mock TranscriptionService transcriptionService;
|
||||
@InjectMocks CommentService commentService;
|
||||
|
||||
// ─── postComment ──────────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void postComment_capturesAuthorNameAtWriteTime() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder()
|
||||
.id(UUID.randomUUID()).email("hans@example.com").firstName("Hans").lastName("Müller").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).authorName("Hans Müller").content("Test").build();
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
DocumentComment result = commentService.postComment(docId, null, "Test", List.of(), author);
|
||||
|
||||
assertThat(result.getAuthorName()).isEqualTo("Hans Müller");
|
||||
}
|
||||
|
||||
@Test
|
||||
void postComment_fallsBackToUsername_whenNamesAreBlank() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("hans42@example.com").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).authorName("hans42").content("Test").build();
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
DocumentComment result = commentService.postComment(docId, null, "Test", List.of(), author);
|
||||
|
||||
assertThat(result.getAuthorName()).isEqualTo("hans42");
|
||||
}
|
||||
|
||||
@Test
|
||||
void postComment_triggersNotifyMentions_whenMentionedUserIdsProvided() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID mentionedId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("hans@example.com").firstName("Hans").lastName("M").build();
|
||||
AppUser mentioned = AppUser.builder().id(mentionedId).email("anna@example.com").firstName("Anna").lastName("S").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).authorName("Hans M").content("Hey @Anna S").build();
|
||||
|
||||
when(userService.findAllById(List.of(mentionedId))).thenReturn(List.of(mentioned));
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
commentService.postComment(docId, null, "Hey @Anna S", List.of(mentionedId), author);
|
||||
|
||||
verify(notificationService).notifyMentions(eq(List.of(mentionedId)), eq(saved));
|
||||
}
|
||||
|
||||
// ─── replyToComment ───────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
@@ -224,7 +178,7 @@ class CommentServiceTest {
|
||||
.id(commentId).documentId(docId).authorId(authorId)
|
||||
.content("Original").authorName("Hans").createdAt(created).build();
|
||||
when(commentRepository.findById(commentId)).thenReturn(Optional.of(comment));
|
||||
when(commentRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
|
||||
stubSaveAssigningRandomId();
|
||||
|
||||
DocumentComment result = commentService.editComment(docId, commentId, "Updated", author);
|
||||
|
||||
@@ -284,28 +238,6 @@ class CommentServiceTest {
|
||||
verify(commentRepository).delete(comment);
|
||||
}
|
||||
|
||||
// ─── getCommentsForDocument ───────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void getCommentsForDocument_returnsRootsWithRepliesAttached() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID rootId = UUID.randomUUID();
|
||||
|
||||
DocumentComment root = DocumentComment.builder()
|
||||
.id(rootId).documentId(docId).authorName("Hans").content("Root").build();
|
||||
DocumentComment reply = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).parentId(rootId).authorName("Anna").content("Reply").build();
|
||||
|
||||
when(commentRepository.findByDocumentIdAndAnnotationIdIsNullAndParentIdIsNull(docId))
|
||||
.thenReturn(List.of(root));
|
||||
when(commentRepository.findByParentId(rootId)).thenReturn(List.of(reply));
|
||||
|
||||
List<DocumentComment> result = commentService.getCommentsForDocument(docId);
|
||||
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0).getReplies()).containsExactly(reply);
|
||||
}
|
||||
|
||||
// ─── replyToComment — reply with null authorId in thread ─────────────────
|
||||
|
||||
@Test
|
||||
@@ -332,82 +264,6 @@ class CommentServiceTest {
|
||||
verify(notificationService).notifyReply(eq(saved), anySet());
|
||||
}
|
||||
|
||||
// ─── resolveAuthorName edge cases ─────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void postComment_fallsBackToUsername_whenFirstNameBlankAndLastNameNull() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("user42@example.com")
|
||||
.firstName(" ").lastName(null).build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).authorName("user42").content("Hi").build();
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
DocumentComment result = commentService.postComment(docId, null, "Hi", List.of(), author);
|
||||
|
||||
assertThat(result.getAuthorName()).isEqualTo("user42");
|
||||
}
|
||||
|
||||
@Test
|
||||
void postComment_fallsBackToUsername_whenFirstNameNullAndLastNameBlank() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("user42@example.com")
|
||||
.firstName(null).lastName(" ").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).authorName("user42").content("Hi").build();
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
DocumentComment result = commentService.postComment(docId, null, "Hi", List.of(), author);
|
||||
|
||||
assertThat(result.getAuthorName()).isEqualTo("user42");
|
||||
}
|
||||
|
||||
@Test
|
||||
void postComment_includesOnlyFirstName_whenLastNameIsNull() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("user42@example.com")
|
||||
.firstName("Hans").lastName(null).build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).authorName("Hans").content("Hi").build();
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
commentService.postComment(docId, null, "Hi", List.of(), author);
|
||||
|
||||
// first != null && !blank → true; last == null → entire condition false → returns stripped first
|
||||
verify(commentRepository).save(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void postComment_includesOnlyLastName_whenFirstNameIsNull() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("user42@example.com")
|
||||
.firstName(null).lastName("Müller").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).authorName("Müller").content("Hi").build();
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
commentService.postComment(docId, null, "Hi", List.of(), author);
|
||||
|
||||
// No exception — name resolution with null first name strips cleanly
|
||||
verify(commentRepository).save(any());
|
||||
}
|
||||
|
||||
// ─── saveMentions — null/empty guard ─────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void postComment_doesNotCallUserService_whenMentionedUserIdsIsNull() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("hans@example.com")
|
||||
.firstName("Hans").lastName("M").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).authorName("Hans M").content("Hi").build();
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
commentService.postComment(docId, null, "Hi", null, author);
|
||||
|
||||
verify(userService, never()).findAllById(anyList());
|
||||
}
|
||||
|
||||
// ─── collectParticipantIds — non-null authorId in reply ──────────────────
|
||||
|
||||
@Test
|
||||
@@ -461,26 +317,6 @@ class CommentServiceTest {
|
||||
verify(notificationService).notifyReply(eq(saved), anySet());
|
||||
}
|
||||
|
||||
// ─── getCommentsForAnnotation ─────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void getCommentsForAnnotation_returnsRootsForAnnotation() {
|
||||
UUID annotationId = UUID.randomUUID();
|
||||
UUID rootId = UUID.randomUUID();
|
||||
|
||||
DocumentComment root = DocumentComment.builder()
|
||||
.id(rootId).annotationId(annotationId).authorName("Hans").content("Root").build();
|
||||
|
||||
when(commentRepository.findByAnnotationIdAndParentIdIsNull(annotationId))
|
||||
.thenReturn(List.of(root));
|
||||
when(commentRepository.findByParentId(rootId)).thenReturn(List.of());
|
||||
|
||||
List<DocumentComment> result = commentService.getCommentsForAnnotation(annotationId);
|
||||
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0).getAnnotationId()).isEqualTo(annotationId);
|
||||
}
|
||||
|
||||
// ─── helpers ──────────────────────────────────────────────────────────────
|
||||
|
||||
private AppUser buildAdmin() {
|
||||
@@ -497,65 +333,6 @@ class CommentServiceTest {
|
||||
|
||||
// ─── audit: COMMENT_ADDED and MENTION_CREATED ─────────────────────────────
|
||||
|
||||
@Test
|
||||
void postComment_logsCommentAdded() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID savedId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("hans@example.com").firstName("Hans").lastName("M").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(savedId).documentId(docId).authorName("Hans M").content("Hello").build();
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
commentService.postComment(docId, null, "Hello", List.of(), author);
|
||||
|
||||
verify(auditService).logAfterCommit(
|
||||
eq(AuditKind.COMMENT_ADDED),
|
||||
eq(author.getId()),
|
||||
eq(docId),
|
||||
argThat(p -> savedId.toString().equals(p.get("commentId"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void postComment_logsMentionCreated_oncePerMentionedUser() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID savedId = UUID.randomUUID();
|
||||
UUID mentionedId1 = UUID.randomUUID();
|
||||
UUID mentionedId2 = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("hans@example.com").firstName("Hans").lastName("M").build();
|
||||
AppUser mentioned1 = AppUser.builder().id(mentionedId1).email("anna@example.com").firstName("Anna").lastName("S").build();
|
||||
AppUser mentioned2 = AppUser.builder().id(mentionedId2).email("bob@example.com").firstName("Bob").lastName("J").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(savedId).documentId(docId).authorName("Hans M").content("Hey @Anna @Bob").build();
|
||||
when(userService.findAllById(List.of(mentionedId1, mentionedId2))).thenReturn(List.of(mentioned1, mentioned2));
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
commentService.postComment(docId, null, "Hey @Anna @Bob", List.of(mentionedId1, mentionedId2), author);
|
||||
|
||||
verify(auditService).logAfterCommit(
|
||||
eq(AuditKind.MENTION_CREATED),
|
||||
eq(author.getId()),
|
||||
eq(docId),
|
||||
argThat(p -> mentionedId1.toString().equals(p.get("mentionedUserId"))));
|
||||
verify(auditService).logAfterCommit(
|
||||
eq(AuditKind.MENTION_CREATED),
|
||||
eq(author.getId()),
|
||||
eq(docId),
|
||||
argThat(p -> mentionedId2.toString().equals(p.get("mentionedUserId"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void postComment_doesNotLogMentionCreated_whenNoMentions() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("hans@example.com").firstName("Hans").lastName("M").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).authorName("Hans M").content("Hello").build();
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
commentService.postComment(docId, null, "Hello", List.of(), author);
|
||||
|
||||
verify(auditService, never()).logAfterCommit(eq(AuditKind.MENTION_CREATED), any(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void replyToComment_logsCommentAdded() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
@@ -699,4 +476,182 @@ class CommentServiceTest {
|
||||
.isInstanceOf(DomainException.class)
|
||||
.hasMessageContaining("Transcription block not found");
|
||||
}
|
||||
|
||||
// ─── postBlockComment — authorName resolution ────────────────────────────
|
||||
|
||||
@Test
|
||||
void postBlockComment_capturesAuthorNameAtWriteTime() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID blockId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder()
|
||||
.id(UUID.randomUUID()).email("hans@example.com").firstName("Hans").lastName("Müller").build();
|
||||
stubBlock(docId, blockId);
|
||||
stubSaveAssigningRandomId();
|
||||
|
||||
DocumentComment result = commentService.postBlockComment(docId, blockId, "Test", List.of(), author);
|
||||
|
||||
assertThat(result.getAuthorName()).isEqualTo("Hans Müller");
|
||||
}
|
||||
|
||||
@Test
|
||||
void postBlockComment_fallsBackToEmail_whenNamesAreBlank() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID blockId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("hans42@example.com").build();
|
||||
stubBlock(docId, blockId);
|
||||
stubSaveAssigningRandomId();
|
||||
|
||||
DocumentComment result = commentService.postBlockComment(docId, blockId, "Test", List.of(), author);
|
||||
|
||||
assertThat(result.getAuthorName()).isEqualTo("hans42@example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void postBlockComment_fallsBackToEmail_whenFirstNameBlankAndLastNameNull() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID blockId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("user42@example.com")
|
||||
.firstName(" ").lastName(null).build();
|
||||
stubBlock(docId, blockId);
|
||||
stubSaveAssigningRandomId();
|
||||
|
||||
DocumentComment result = commentService.postBlockComment(docId, blockId, "Hi", List.of(), author);
|
||||
|
||||
assertThat(result.getAuthorName()).isEqualTo("user42@example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void postBlockComment_fallsBackToEmail_whenFirstNameNullAndLastNameBlank() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID blockId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("user42@example.com")
|
||||
.firstName(null).lastName(" ").build();
|
||||
stubBlock(docId, blockId);
|
||||
stubSaveAssigningRandomId();
|
||||
|
||||
DocumentComment result = commentService.postBlockComment(docId, blockId, "Hi", List.of(), author);
|
||||
|
||||
assertThat(result.getAuthorName()).isEqualTo("user42@example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void postBlockComment_usesFirstNameAlone_whenLastNameIsNull() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID blockId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("user42@example.com")
|
||||
.firstName("Hans").lastName(null).build();
|
||||
stubBlock(docId, blockId);
|
||||
stubSaveAssigningRandomId();
|
||||
|
||||
DocumentComment result = commentService.postBlockComment(docId, blockId, "Hi", List.of(), author);
|
||||
|
||||
assertThat(result.getAuthorName()).isEqualTo("Hans");
|
||||
}
|
||||
|
||||
@Test
|
||||
void postBlockComment_usesLastNameAlone_whenFirstNameIsNull() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID blockId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("user42@example.com")
|
||||
.firstName(null).lastName("Müller").build();
|
||||
stubBlock(docId, blockId);
|
||||
stubSaveAssigningRandomId();
|
||||
|
||||
DocumentComment result = commentService.postBlockComment(docId, blockId, "Hi", List.of(), author);
|
||||
|
||||
assertThat(result.getAuthorName()).isEqualTo("Müller");
|
||||
}
|
||||
|
||||
// ─── postBlockComment — mentions ─────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void postBlockComment_triggersNotifyMentions_whenMentionedUserIdsProvided() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID blockId = UUID.randomUUID();
|
||||
UUID mentionedId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("hans@example.com").firstName("Hans").lastName("M").build();
|
||||
AppUser mentioned = AppUser.builder().id(mentionedId).email("anna@example.com").firstName("Anna").lastName("S").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).blockId(blockId).authorName("Hans M").content("Hey @Anna S").build();
|
||||
stubBlock(docId, blockId);
|
||||
when(userService.findAllById(List.of(mentionedId))).thenReturn(List.of(mentioned));
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
commentService.postBlockComment(docId, blockId, "Hey @Anna S", List.of(mentionedId), author);
|
||||
|
||||
verify(notificationService).notifyMentions(eq(List.of(mentionedId)), eq(saved));
|
||||
}
|
||||
|
||||
@Test
|
||||
void postBlockComment_doesNotCallUserService_whenMentionedUserIdsIsNull() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID blockId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("hans@example.com")
|
||||
.firstName("Hans").lastName("M").build();
|
||||
stubBlock(docId, blockId);
|
||||
stubSaveAssigningRandomId();
|
||||
|
||||
commentService.postBlockComment(docId, blockId, "Hi", null, author);
|
||||
|
||||
verify(userService, never()).findAllById(anyList());
|
||||
}
|
||||
|
||||
@Test
|
||||
void postBlockComment_logsMentionCreated_oncePerMentionedUser() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID blockId = UUID.randomUUID();
|
||||
UUID savedId = UUID.randomUUID();
|
||||
UUID mentionedId1 = UUID.randomUUID();
|
||||
UUID mentionedId2 = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("hans@example.com").firstName("Hans").lastName("M").build();
|
||||
AppUser mentioned1 = AppUser.builder().id(mentionedId1).email("anna@example.com").firstName("Anna").lastName("S").build();
|
||||
AppUser mentioned2 = AppUser.builder().id(mentionedId2).email("bob@example.com").firstName("Bob").lastName("J").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(savedId).documentId(docId).blockId(blockId).authorName("Hans M").content("Hey @Anna @Bob").build();
|
||||
stubBlock(docId, blockId);
|
||||
when(userService.findAllById(List.of(mentionedId1, mentionedId2))).thenReturn(List.of(mentioned1, mentioned2));
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
commentService.postBlockComment(docId, blockId, "Hey @Anna @Bob", List.of(mentionedId1, mentionedId2), author);
|
||||
|
||||
verify(auditService).logAfterCommit(
|
||||
eq(AuditKind.MENTION_CREATED),
|
||||
eq(author.getId()),
|
||||
eq(docId),
|
||||
argThat(p -> mentionedId1.toString().equals(p.get("mentionedUserId"))));
|
||||
verify(auditService).logAfterCommit(
|
||||
eq(AuditKind.MENTION_CREATED),
|
||||
eq(author.getId()),
|
||||
eq(docId),
|
||||
argThat(p -> mentionedId2.toString().equals(p.get("mentionedUserId"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void postBlockComment_doesNotLogMentionCreated_whenNoMentions() {
|
||||
UUID docId = UUID.randomUUID();
|
||||
UUID blockId = UUID.randomUUID();
|
||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("hans@example.com").firstName("Hans").lastName("M").build();
|
||||
DocumentComment saved = DocumentComment.builder()
|
||||
.id(UUID.randomUUID()).documentId(docId).blockId(blockId).authorName("Hans M").content("Hello").build();
|
||||
stubBlock(docId, blockId);
|
||||
when(commentRepository.save(any())).thenReturn(saved);
|
||||
|
||||
commentService.postBlockComment(docId, blockId, "Hello", List.of(), author);
|
||||
|
||||
verify(auditService, never()).logAfterCommit(eq(AuditKind.MENTION_CREATED), any(), any(), any());
|
||||
}
|
||||
|
||||
private void stubBlock(UUID docId, UUID blockId) {
|
||||
when(transcriptionService.getBlock(docId, blockId))
|
||||
.thenReturn(TranscriptionBlock.builder()
|
||||
.id(blockId).documentId(docId).annotationId(UUID.randomUUID()).sortOrder(0).build());
|
||||
}
|
||||
|
||||
private void stubSaveAssigningRandomId() {
|
||||
when(commentRepository.save(any())).thenAnswer(inv -> {
|
||||
DocumentComment c = inv.getArgument(0);
|
||||
if (c.getId() == null) c.setId(UUID.randomUUID());
|
||||
return c;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user