diff --git a/backend/src/main/java/org/raddatz/familienarchiv/model/TranscriptionBlock.java b/backend/src/main/java/org/raddatz/familienarchiv/model/TranscriptionBlock.java index 3ff9ca78..6d3e167d 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/model/TranscriptionBlock.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/model/TranscriptionBlock.java @@ -35,7 +35,9 @@ public class TranscriptionBlock { @Column(columnDefinition = "TEXT") private String text; - @ElementCollection(fetch = FetchType.LAZY) + // EAGER: mention set is bounded by block text length (typically < 20 entries). + // Switching back to LAZY requires callers to be inside an open Hibernate session. + @ElementCollection(fetch = FetchType.EAGER) @CollectionTable( name = "transcription_block_mentioned_persons", joinColumns = @JoinColumn(name = "block_id")) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/service/TranscriptionService.java b/backend/src/main/java/org/raddatz/familienarchiv/service/TranscriptionService.java index 589e7f56..b96f1a2a 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/service/TranscriptionService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/TranscriptionService.java @@ -134,6 +134,8 @@ public class TranscriptionService { if (dto.getLabel() != null) { block.setLabel(dto.getLabel()); } + block.getMentionedPersons().clear(); + block.getMentionedPersons().addAll(dto.getMentionedPersons()); block.setUpdatedBy(userId); TranscriptionBlock saved = blockRepository.save(block); diff --git a/backend/src/test/java/org/raddatz/familienarchiv/service/TranscriptionServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/service/TranscriptionServiceTest.java index 8aa6ee99..15a098c0 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/service/TranscriptionServiceTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/service/TranscriptionServiceTest.java @@ -17,6 +17,7 @@ import org.raddatz.familienarchiv.model.BlockSource; import org.raddatz.familienarchiv.model.Document; import org.raddatz.familienarchiv.model.DocumentAnnotation; import org.raddatz.familienarchiv.model.Person; +import org.raddatz.familienarchiv.model.PersonMention; import org.raddatz.familienarchiv.model.ScriptType; import org.raddatz.familienarchiv.model.TranscriptionBlock; import org.raddatz.familienarchiv.model.TranscriptionBlockVersion; @@ -215,6 +216,60 @@ class TranscriptionServiceTest { assertThat(result.getSource()).isEqualTo(BlockSource.MANUAL); } + @Test + void updateBlock_replacesMentionedPersonsFromDto() { + UUID docId = UUID.randomUUID(); + UUID blockId = UUID.randomUUID(); + UUID personId = UUID.randomUUID(); + + TranscriptionBlock block = TranscriptionBlock.builder() + .id(blockId).documentId(docId).text("old").build(); + when(blockRepository.findByIdAndDocumentId(blockId, docId)).thenReturn(Optional.of(block)); + when(blockRepository.save(any())).thenAnswer(inv -> inv.getArgument(0)); + when(documentService.getDocumentById(any())).thenReturn( + Document.builder().scriptType(ScriptType.TYPEWRITER).build()); + + PersonMention mention = new PersonMention(personId, "Auguste"); + UpdateTranscriptionBlockDTO dto = UpdateTranscriptionBlockDTO.builder() + .text("@Auguste text") + .mentionedPersons(List.of(mention)) + .build(); + + TranscriptionBlock result = transcriptionService.updateBlock(docId, blockId, dto, UUID.randomUUID()); + + assertThat(result.getMentionedPersons()) + .containsExactly(mention); + } + + @Test + void updateBlock_clearsPriorMentions_beforeApplyingDto() { + UUID docId = UUID.randomUUID(); + UUID blockId = UUID.randomUUID(); + + PersonMention prior = new PersonMention(UUID.randomUUID(), "Heinrich"); + PersonMention incoming = new PersonMention(UUID.randomUUID(), "Auguste"); + + TranscriptionBlock block = TranscriptionBlock.builder() + .id(blockId).documentId(docId).text("old").build(); + block.getMentionedPersons().add(prior); + + when(blockRepository.findByIdAndDocumentId(blockId, docId)).thenReturn(Optional.of(block)); + when(blockRepository.save(any())).thenAnswer(inv -> inv.getArgument(0)); + when(documentService.getDocumentById(any())).thenReturn( + Document.builder().scriptType(ScriptType.TYPEWRITER).build()); + + UpdateTranscriptionBlockDTO dto = UpdateTranscriptionBlockDTO.builder() + .text("@Auguste text") + .mentionedPersons(List.of(incoming)) + .build(); + + TranscriptionBlock result = transcriptionService.updateBlock(docId, blockId, dto, UUID.randomUUID()); + + assertThat(result.getMentionedPersons()) + .containsExactly(incoming) + .doesNotContain(prior); + } + @Test void updateBlock_triggersTraining_whenKurrentSenderPresent() { UUID docId = UUID.randomUUID(); diff --git a/frontend/src/lib/components/MentionDropdown.svelte b/frontend/src/lib/components/MentionDropdown.svelte index d86e912a..6a95b233 100644 --- a/frontend/src/lib/components/MentionDropdown.svelte +++ b/frontend/src/lib/components/MentionDropdown.svelte @@ -111,7 +111,7 @@ function selectItem(item: Person) { unauthenticated users. -->