fix(comment): populate annotationId on block comments from the block
postBlockComment now looks up the block via TranscriptionService and sets comment.annotationId from block.getAnnotationId(). This closes the upstream root cause of issue #276, where notifications for block comments were stored with annotationId=null, breaking the notification deep-link flow on the document detail page. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import org.raddatz.familienarchiv.exception.DomainException;
|
|||||||
import org.raddatz.familienarchiv.exception.ErrorCode;
|
import org.raddatz.familienarchiv.exception.ErrorCode;
|
||||||
import org.raddatz.familienarchiv.model.AppUser;
|
import org.raddatz.familienarchiv.model.AppUser;
|
||||||
import org.raddatz.familienarchiv.model.DocumentComment;
|
import org.raddatz.familienarchiv.model.DocumentComment;
|
||||||
|
import org.raddatz.familienarchiv.model.TranscriptionBlock;
|
||||||
import org.raddatz.familienarchiv.repository.CommentRepository;
|
import org.raddatz.familienarchiv.repository.CommentRepository;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -26,6 +27,7 @@ public class CommentService {
|
|||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
private final NotificationService notificationService;
|
private final NotificationService notificationService;
|
||||||
private final AuditService auditService;
|
private final AuditService auditService;
|
||||||
|
private final TranscriptionService transcriptionService;
|
||||||
|
|
||||||
public List<DocumentComment> getCommentsForDocument(UUID documentId) {
|
public List<DocumentComment> getCommentsForDocument(UUID documentId) {
|
||||||
List<DocumentComment> roots =
|
List<DocumentComment> roots =
|
||||||
@@ -46,9 +48,11 @@ public class CommentService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public DocumentComment postBlockComment(UUID documentId, UUID blockId, String content,
|
public DocumentComment postBlockComment(UUID documentId, UUID blockId, String content,
|
||||||
List<UUID> mentionedUserIds, AppUser author) {
|
List<UUID> mentionedUserIds, AppUser author) {
|
||||||
|
TranscriptionBlock block = transcriptionService.getBlock(documentId, blockId);
|
||||||
DocumentComment comment = DocumentComment.builder()
|
DocumentComment comment = DocumentComment.builder()
|
||||||
.documentId(documentId)
|
.documentId(documentId)
|
||||||
.blockId(blockId)
|
.blockId(blockId)
|
||||||
|
.annotationId(block.getAnnotationId())
|
||||||
.content(content)
|
.content(content)
|
||||||
.authorId(author.getId())
|
.authorId(author.getId())
|
||||||
.authorName(resolveAuthorName(author))
|
.authorName(resolveAuthorName(author))
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.raddatz.familienarchiv.audit.AuditService;
|
|||||||
import org.raddatz.familienarchiv.exception.DomainException;
|
import org.raddatz.familienarchiv.exception.DomainException;
|
||||||
import org.raddatz.familienarchiv.model.AppUser;
|
import org.raddatz.familienarchiv.model.AppUser;
|
||||||
import org.raddatz.familienarchiv.model.DocumentComment;
|
import org.raddatz.familienarchiv.model.DocumentComment;
|
||||||
|
import org.raddatz.familienarchiv.model.TranscriptionBlock;
|
||||||
import org.raddatz.familienarchiv.model.UserGroup;
|
import org.raddatz.familienarchiv.model.UserGroup;
|
||||||
import org.raddatz.familienarchiv.repository.CommentRepository;
|
import org.raddatz.familienarchiv.repository.CommentRepository;
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@ class CommentServiceTest {
|
|||||||
@Mock UserService userService;
|
@Mock UserService userService;
|
||||||
@Mock NotificationService notificationService;
|
@Mock NotificationService notificationService;
|
||||||
@Mock AuditService auditService;
|
@Mock AuditService auditService;
|
||||||
|
@Mock TranscriptionService transcriptionService;
|
||||||
@InjectMocks CommentService commentService;
|
@InjectMocks CommentService commentService;
|
||||||
|
|
||||||
// ─── postComment ──────────────────────────────────────────────────────────
|
// ─── postComment ──────────────────────────────────────────────────────────
|
||||||
@@ -611,6 +613,8 @@ class CommentServiceTest {
|
|||||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("felix@example.com").firstName("Felix").lastName("B").build();
|
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("felix@example.com").firstName("Felix").lastName("B").build();
|
||||||
DocumentComment saved = DocumentComment.builder()
|
DocumentComment saved = DocumentComment.builder()
|
||||||
.id(savedId).documentId(docId).blockId(blockId).authorName("Felix B").content("Nice").build();
|
.id(savedId).documentId(docId).blockId(blockId).authorName("Felix B").content("Nice").build();
|
||||||
|
when(transcriptionService.getBlock(docId, blockId))
|
||||||
|
.thenReturn(TranscriptionBlock.builder().id(blockId).documentId(docId).annotationId(UUID.randomUUID()).sortOrder(0).build());
|
||||||
when(commentRepository.save(any())).thenReturn(saved);
|
when(commentRepository.save(any())).thenReturn(saved);
|
||||||
|
|
||||||
commentService.postBlockComment(docId, blockId, "Nice", List.of(), author);
|
commentService.postBlockComment(docId, blockId, "Nice", List.of(), author);
|
||||||
@@ -643,7 +647,10 @@ class CommentServiceTest {
|
|||||||
void postBlockComment_setsBlockIdOnComment() {
|
void postBlockComment_setsBlockIdOnComment() {
|
||||||
UUID documentId = UUID.randomUUID();
|
UUID documentId = UUID.randomUUID();
|
||||||
UUID blockId = UUID.randomUUID();
|
UUID blockId = UUID.randomUUID();
|
||||||
|
UUID annotationId = UUID.randomUUID();
|
||||||
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("felix@example.com").firstName("Felix").lastName("Brandt").build();
|
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("felix@example.com").firstName("Felix").lastName("Brandt").build();
|
||||||
|
when(transcriptionService.getBlock(documentId, blockId))
|
||||||
|
.thenReturn(TranscriptionBlock.builder().id(blockId).documentId(documentId).annotationId(annotationId).sortOrder(0).build());
|
||||||
when(commentRepository.save(any())).thenAnswer(inv -> {
|
when(commentRepository.save(any())).thenAnswer(inv -> {
|
||||||
DocumentComment c = inv.getArgument(0);
|
DocumentComment c = inv.getArgument(0);
|
||||||
c.setId(UUID.randomUUID());
|
c.setId(UUID.randomUUID());
|
||||||
@@ -657,4 +664,39 @@ class CommentServiceTest {
|
|||||||
assertThat(result.getDocumentId()).isEqualTo(documentId);
|
assertThat(result.getDocumentId()).isEqualTo(documentId);
|
||||||
assertThat(result.getContent()).isEqualTo("Looks like Breslau");
|
assertThat(result.getContent()).isEqualTo("Looks like Breslau");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void postBlockComment_setsAnnotationIdFromBlock() {
|
||||||
|
UUID documentId = UUID.randomUUID();
|
||||||
|
UUID blockId = UUID.randomUUID();
|
||||||
|
UUID annotationId = UUID.randomUUID();
|
||||||
|
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("felix@example.com").firstName("Felix").lastName("Brandt").build();
|
||||||
|
when(transcriptionService.getBlock(documentId, blockId))
|
||||||
|
.thenReturn(TranscriptionBlock.builder().id(blockId).documentId(documentId).annotationId(annotationId).sortOrder(0).build());
|
||||||
|
when(commentRepository.save(any())).thenAnswer(inv -> {
|
||||||
|
DocumentComment c = inv.getArgument(0);
|
||||||
|
c.setId(UUID.randomUUID());
|
||||||
|
return c;
|
||||||
|
});
|
||||||
|
|
||||||
|
DocumentComment result = commentService.postBlockComment(
|
||||||
|
documentId, blockId, "Nice work", List.of(), author);
|
||||||
|
|
||||||
|
assertThat(result.getAnnotationId()).isEqualTo(annotationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void postBlockComment_propagatesNotFound_whenBlockDoesNotExist() {
|
||||||
|
UUID documentId = UUID.randomUUID();
|
||||||
|
UUID blockId = UUID.randomUUID();
|
||||||
|
AppUser author = AppUser.builder().id(UUID.randomUUID()).email("felix@example.com").firstName("Felix").lastName("Brandt").build();
|
||||||
|
when(transcriptionService.getBlock(documentId, blockId))
|
||||||
|
.thenThrow(DomainException.notFound(
|
||||||
|
org.raddatz.familienarchiv.exception.ErrorCode.TRANSCRIPTION_BLOCK_NOT_FOUND,
|
||||||
|
"Transcription block not found: " + blockId));
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> commentService.postBlockComment(documentId, blockId, "Hi", List.of(), author))
|
||||||
|
.isInstanceOf(DomainException.class)
|
||||||
|
.hasMessageContaining("Transcription block not found");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user