Implement GET /events/{token} backend with timezone support

Domain: add timezone field to Event and CreateEventCommand.
Ports: new GetEventUseCase inbound port.
Service: implement getByEventToken, validate IANA timezone on create.
Controller: map to GetEventResponse, compute expired flag via Clock.
Persistence: timezone column in JPA entity and mapping.
Tests: integration tests use DTOs + ObjectMapper instead of inline JSON,
GET tests seed DB directly via JpaRepository for isolation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 22:33:40 +01:00
parent e77e479e2a
commit e5d0dd5f8f
13 changed files with 391 additions and 99 deletions
@@ -16,6 +16,8 @@ import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Optional;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -50,6 +52,7 @@ class EventServiceTest {
"Birthday Party",
"Come celebrate!",
OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2)),
ZoneId.of("Europe/Berlin"),
"Berlin",
LocalDate.of(2026, 7, 15)
);
@@ -58,28 +61,13 @@ class EventServiceTest {
assertThat(result.getTitle()).isEqualTo("Birthday Party");
assertThat(result.getDescription()).isEqualTo("Come celebrate!");
assertThat(result.getTimezone()).isEqualTo(ZoneId.of("Europe/Berlin"));
assertThat(result.getLocation()).isEqualTo("Berlin");
assertThat(result.getEventToken()).isNotNull();
assertThat(result.getOrganizerToken()).isNotNull();
assertThat(result.getCreatedAt()).isEqualTo(OffsetDateTime.now(FIXED_CLOCK));
}
@Test
void eventTokenAndOrganizerTokenAreDifferent() {
when(eventRepository.save(any(Event.class)))
.thenAnswer(invocation -> invocation.getArgument(0));
var command = new CreateEventCommand(
"Test", null,
OffsetDateTime.now(FIXED_CLOCK).plusDays(1), null,
LocalDate.now(FIXED_CLOCK).plusDays(30)
);
Event result = eventService.createEvent(command);
assertThat(result.getEventToken()).isNotEqualTo(result.getOrganizerToken());
}
@Test
void repositorySaveCalledExactlyOnce() {
when(eventRepository.save(any(Event.class)))
@@ -87,7 +75,7 @@ class EventServiceTest {
var command = new CreateEventCommand(
"Test", null,
OffsetDateTime.now(FIXED_CLOCK).plusDays(1), null,
OffsetDateTime.now(FIXED_CLOCK).plusDays(1), ZONE, null,
LocalDate.now(FIXED_CLOCK).plusDays(30)
);
@@ -102,7 +90,7 @@ class EventServiceTest {
void expiryDateTodayThrowsException() {
var command = new CreateEventCommand(
"Test", null,
OffsetDateTime.now(FIXED_CLOCK).plusDays(1), null,
OffsetDateTime.now(FIXED_CLOCK).plusDays(1), ZONE, null,
LocalDate.now(FIXED_CLOCK)
);
@@ -114,7 +102,7 @@ class EventServiceTest {
void expiryDateInPastThrowsException() {
var command = new CreateEventCommand(
"Test", null,
OffsetDateTime.now(FIXED_CLOCK).plusDays(1), null,
OffsetDateTime.now(FIXED_CLOCK).plusDays(1), ZONE, null,
LocalDate.now(FIXED_CLOCK).minusDays(5)
);
@@ -129,7 +117,7 @@ class EventServiceTest {
var command = new CreateEventCommand(
"Test", null,
OffsetDateTime.now(FIXED_CLOCK).plusDays(1), null,
OffsetDateTime.now(FIXED_CLOCK).plusDays(1), ZONE, null,
LocalDate.now(FIXED_CLOCK).plusDays(1)
);
@@ -137,4 +125,51 @@ class EventServiceTest {
assertThat(result.getExpiryDate()).isEqualTo(LocalDate.of(2026, 3, 6));
}
// --- GetEventUseCase tests (T004) ---
@Test
void getByEventTokenReturnsEvent() {
UUID token = UUID.randomUUID();
var event = new Event();
event.setEventToken(token);
event.setTitle("Found Event");
when(eventRepository.findByEventToken(token))
.thenReturn(Optional.of(event));
Optional<Event> result = eventService.getByEventToken(token);
assertThat(result).isPresent();
assertThat(result.get().getTitle()).isEqualTo("Found Event");
}
@Test
void getByEventTokenReturnsEmptyForUnknownToken() {
UUID token = UUID.randomUUID();
when(eventRepository.findByEventToken(token))
.thenReturn(Optional.empty());
Optional<Event> result = eventService.getByEventToken(token);
assertThat(result).isEmpty();
}
// --- Timezone validation tests (T006) ---
@Test
void createEventWithValidTimezoneSucceeds() {
when(eventRepository.save(any(Event.class)))
.thenAnswer(invocation -> invocation.getArgument(0));
var command = new CreateEventCommand(
"Test", null,
OffsetDateTime.now(FIXED_CLOCK).plusDays(1),
ZoneId.of("America/New_York"), null,
LocalDate.now(FIXED_CLOCK).plusDays(30)
);
Event result = eventService.createEvent(command);
assertThat(result.getTimezone()).isEqualTo(ZoneId.of("America/New_York"));
}
}