diff --git a/backend/src/main/java/org/raddatz/familienarchiv/service/PersonService.java b/backend/src/main/java/org/raddatz/familienarchiv/service/PersonService.java index df04aa38..c83050ac 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/service/PersonService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/service/PersonService.java @@ -13,11 +13,13 @@ import org.raddatz.familienarchiv.dto.PersonUpdateDTO; import org.raddatz.familienarchiv.exception.DomainException; import org.raddatz.familienarchiv.exception.ErrorCode; import org.raddatz.familienarchiv.model.Person; +import org.raddatz.familienarchiv.model.PersonDisplayNameChangedEvent; import org.raddatz.familienarchiv.model.PersonNameAlias; import org.raddatz.familienarchiv.model.PersonNameAliasType; import org.raddatz.familienarchiv.model.PersonType; import org.raddatz.familienarchiv.repository.PersonNameAliasRepository; import org.raddatz.familienarchiv.repository.PersonRepository; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -31,6 +33,7 @@ public class PersonService { private final PersonRepository personRepository; private final PersonNameAliasRepository aliasRepository; + private final ApplicationEventPublisher eventPublisher; public List findAll(String q) { if (q == null) { @@ -157,6 +160,7 @@ public class PersonService { validateYears(dto.getBirthYear(), dto.getDeathYear()); Person person = personRepository.findById(id) .orElseThrow(() -> DomainException.notFound(ErrorCode.PERSON_NOT_FOUND, "Person not found: " + id)); + String oldDisplayName = person.getDisplayName(); person.setPersonType(dto.getPersonType()); person.setTitle(dto.getTitle() == null || dto.getTitle().isBlank() ? null : dto.getTitle().trim()); person.setFirstName(dto.getFirstName()); @@ -165,7 +169,12 @@ public class PersonService { person.setNotes(dto.getNotes() == null || dto.getNotes().isBlank() ? null : dto.getNotes().trim()); person.setBirthYear(dto.getBirthYear()); person.setDeathYear(dto.getDeathYear()); - return personRepository.save(person); + Person saved = personRepository.save(person); + String newDisplayName = saved.getDisplayName(); + if (!Objects.equals(oldDisplayName, newDisplayName)) { + eventPublisher.publishEvent(new PersonDisplayNameChangedEvent(id, oldDisplayName, newDisplayName)); + } + return saved; } @Transactional diff --git a/backend/src/test/java/org/raddatz/familienarchiv/service/PersonServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/service/PersonServiceTest.java index da2fdde4..3351fd61 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/service/PersonServiceTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/service/PersonServiceTest.java @@ -2,6 +2,7 @@ package org.raddatz.familienarchiv.service; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -10,11 +11,13 @@ import org.raddatz.familienarchiv.dto.PersonSummaryDTO; import org.raddatz.familienarchiv.dto.PersonUpdateDTO; import org.raddatz.familienarchiv.exception.DomainException; import org.raddatz.familienarchiv.model.Person; +import org.raddatz.familienarchiv.model.PersonDisplayNameChangedEvent; import org.raddatz.familienarchiv.model.PersonNameAlias; import org.raddatz.familienarchiv.model.PersonNameAliasType; import org.raddatz.familienarchiv.model.PersonType; import org.raddatz.familienarchiv.repository.PersonNameAliasRepository; import org.raddatz.familienarchiv.repository.PersonRepository; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.web.server.ResponseStatusException; import java.util.List; @@ -31,6 +34,7 @@ class PersonServiceTest { @Mock PersonRepository personRepository; @Mock PersonNameAliasRepository aliasRepository; + @Mock ApplicationEventPublisher eventPublisher; @InjectMocks PersonService personService; // ─── getById ───────────────────────────────────────────────────────────── @@ -242,6 +246,37 @@ class PersonServiceTest { assertThat(result.getAlias()).isEqualTo("Anna Alt"); } + // ─── updatePerson (display-name change event) ──────────────────────────── + + @Test + void updatePerson_publishesEvent_whenTitleChanges() { + UUID id = UUID.randomUUID(); + Person existing = Person.builder() + .id(id).title("Herr").firstName("Auguste").lastName("Raddatz") + .personType(PersonType.PERSON).build(); + String oldName = existing.getDisplayName(); + + when(personRepository.findById(id)).thenReturn(Optional.of(existing)); + when(personRepository.save(any())).thenAnswer(inv -> inv.getArgument(0)); + + PersonUpdateDTO dto = new PersonUpdateDTO(); + dto.setPersonType(PersonType.PERSON); + dto.setTitle("Frau"); dto.setFirstName("Auguste"); dto.setLastName("Raddatz"); + + personService.updatePerson(id, dto); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(PersonDisplayNameChangedEvent.class); + verify(eventPublisher).publishEvent(captor.capture()); + + PersonDisplayNameChangedEvent event = captor.getValue(); + assertThat(event.personId()).isEqualTo(id); + assertThat(event.oldDisplayName()).isEqualTo(oldName); + assertThat(event.newDisplayName()) + .isNotEqualTo(oldName) + .contains("Frau"); + } + // ─── findOrCreateByAlias ───────────────────────────────────────────────── @Test