diff --git a/backend/src/main/java/org/raddatz/familienarchiv/geschichte/GeschichteController.java b/backend/src/main/java/org/raddatz/familienarchiv/geschichte/GeschichteController.java index b675a2b5..4eed4e16 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/geschichte/GeschichteController.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/geschichte/GeschichteController.java @@ -46,9 +46,7 @@ public class GeschichteController { @GetMapping("/{id}") public GeschichteView getById(@PathVariable UUID id) { - Geschichte g = geschichteService.getById(id); - List items = journeyItemService.getItems(g.getId()); - return geschichteService.toView(g, items); + return geschichteService.getView(id); } @PostMapping diff --git a/backend/src/main/java/org/raddatz/familienarchiv/geschichte/GeschichteService.java b/backend/src/main/java/org/raddatz/familienarchiv/geschichte/GeschichteService.java index 32afda8a..2a0d8819 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/geschichte/GeschichteService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/geschichte/GeschichteService.java @@ -6,6 +6,7 @@ import org.owasp.html.HtmlPolicyBuilder; import org.owasp.html.PolicyFactory; import org.raddatz.familienarchiv.exception.DomainException; import org.raddatz.familienarchiv.exception.ErrorCode; +import org.raddatz.familienarchiv.geschichte.journeyitem.JourneyItemService; import org.raddatz.familienarchiv.geschichte.journeyitem.JourneyItemView; import org.raddatz.familienarchiv.user.AppUser; import org.raddatz.familienarchiv.person.Person; @@ -35,6 +36,7 @@ public class GeschichteService { private final PersonService personService; private final DocumentService documentService; private final UserService userService; + private final JourneyItemService journeyItemService; /** * Allow-list policy for Geschichte body HTML. Tiptap on the writer side @@ -67,6 +69,13 @@ public class GeschichteService { return g; } + @Transactional(readOnly = true) + public GeschichteView getView(UUID id) { + Geschichte g = getById(id); + List items = journeyItemService.getItems(id); + return toView(g, items); + } + GeschichteView toView(Geschichte g, List items) { AppUser author = g.getAuthor(); GeschichteView.AuthorView authorView = null; diff --git a/backend/src/test/java/org/raddatz/familienarchiv/geschichte/GeschichteControllerTest.java b/backend/src/test/java/org/raddatz/familienarchiv/geschichte/GeschichteControllerTest.java index 2aec2e4c..9c7bf25c 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/geschichte/GeschichteControllerTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/geschichte/GeschichteControllerTest.java @@ -106,10 +106,7 @@ class GeschichteControllerTest { @WithMockUser(authorities = "READ_ALL") void getById_returns200_whenFound() throws Exception { UUID id = UUID.randomUUID(); - Geschichte g = published(id, "Hello"); - when(geschichteService.getById(id)).thenReturn(g); - when(journeyItemService.getItems(id)).thenReturn(List.of()); - when(geschichteService.toView(g, List.of())).thenReturn(viewStub(id, "Hello")); + when(geschichteService.getView(id)).thenReturn(viewStub(id, "Hello")); mockMvc.perform(get("/api/geschichten/{id}", id)) .andExpect(status().isOk()) @@ -121,7 +118,7 @@ class GeschichteControllerTest { @WithMockUser(authorities = "READ_ALL") void getById_returns404_whenServiceThrowsNotFound() throws Exception { UUID id = UUID.randomUUID(); - when(geschichteService.getById(id)) + when(geschichteService.getView(id)) .thenThrow(DomainException.notFound(ErrorCode.GESCHICHTE_NOT_FOUND, "x")); mockMvc.perform(get("/api/geschichten/{id}", id)) diff --git a/backend/src/test/java/org/raddatz/familienarchiv/geschichte/GeschichteServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/geschichte/GeschichteServiceTest.java index 3f154cdc..d2d5bfed 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/geschichte/GeschichteServiceTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/geschichte/GeschichteServiceTest.java @@ -9,6 +9,8 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.raddatz.familienarchiv.exception.DomainException; import org.raddatz.familienarchiv.exception.ErrorCode; +import org.raddatz.familienarchiv.geschichte.journeyitem.JourneyItemService; +import org.raddatz.familienarchiv.geschichte.journeyitem.JourneyItemView; import org.raddatz.familienarchiv.user.AppUser; import org.raddatz.familienarchiv.person.Person; import org.raddatz.familienarchiv.security.Permission; @@ -45,6 +47,7 @@ class GeschichteServiceTest { @Mock PersonService personService; @Mock DocumentService documentService; @Mock UserService userService; + @Mock JourneyItemService journeyItemService; @InjectMocks GeschichteService geschichteService; @@ -116,6 +119,36 @@ class GeschichteServiceTest { .isEqualTo(ErrorCode.GESCHICHTE_NOT_FOUND); } + // ─── getView ────────────────────────────────────────────────────────────── + + @Test + void getView_returns_assembled_view_and_delegates_to_journeyItemService() { + authenticateAs(reader, Permission.READ_ALL); + UUID id = UUID.randomUUID(); + Geschichte published = published(id); + JourneyItemView item = new JourneyItemView(UUID.randomUUID(), 10, null, "Note"); + when(geschichteRepository.findById(id)).thenReturn(Optional.of(published)); + when(journeyItemService.getItems(id)).thenReturn(List.of(item)); + + GeschichteView view = geschichteService.getView(id); + + assertThat(view.id()).isEqualTo(id); + assertThat(view.items()).containsExactly(item); + verify(journeyItemService).getItems(id); + } + + @Test + void getView_throws_NOT_FOUND_when_id_unknown() { + authenticateAs(reader, Permission.READ_ALL); + UUID id = UUID.randomUUID(); + when(geschichteRepository.findById(id)).thenReturn(Optional.empty()); + + assertThatThrownBy(() -> geschichteService.getView(id)) + .isInstanceOf(DomainException.class) + .extracting("code") + .isEqualTo(ErrorCode.GESCHICHTE_NOT_FOUND); + } + @Test void toView_author_displayName_uses_firstName_lastName() { UUID id = UUID.randomUUID();