Make expiryDate an internal concern, auto-set to event date + 7 days
The expiry date is no longer user-facing: it is removed from the API (request and response) and the frontend. The backend now automatically calculates it as the event date plus 7 days. The expired banner and RSVP-bar filtering by expired status are also removed from the UI, since expiry is purely an internal data-retention mechanism. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -55,8 +55,7 @@ class EventControllerIntegrationTest {
|
||||
.description("Come celebrate!")
|
||||
.dateTime(OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2)))
|
||||
.timezone("Europe/Berlin")
|
||||
.location("Berlin")
|
||||
.expiryDate(LocalDate.of(2026, 6, 16));
|
||||
.location("Berlin");
|
||||
|
||||
var result = mockMvc.perform(post("/api/events")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
@@ -67,7 +66,6 @@ class EventControllerIntegrationTest {
|
||||
.andExpect(jsonPath("$.title").value("Birthday Party"))
|
||||
.andExpect(jsonPath("$.timezone").value("Europe/Berlin"))
|
||||
.andExpect(jsonPath("$.dateTime").isNotEmpty())
|
||||
.andExpect(jsonPath("$.expiryDate").isNotEmpty())
|
||||
.andReturn();
|
||||
|
||||
var response = objectMapper.readValue(
|
||||
@@ -79,7 +77,7 @@ class EventControllerIntegrationTest {
|
||||
assertThat(persisted.getDescription()).isEqualTo("Come celebrate!");
|
||||
assertThat(persisted.getTimezone()).isEqualTo("Europe/Berlin");
|
||||
assertThat(persisted.getLocation()).isEqualTo("Berlin");
|
||||
assertThat(persisted.getExpiryDate()).isEqualTo(request.getExpiryDate());
|
||||
assertThat(persisted.getExpiryDate()).isEqualTo(LocalDate.of(2026, 6, 22));
|
||||
assertThat(persisted.getDateTime().toInstant())
|
||||
.isEqualTo(request.getDateTime().toInstant());
|
||||
assertThat(persisted.getOrganizerToken()).isNotNull();
|
||||
@@ -91,8 +89,7 @@ class EventControllerIntegrationTest {
|
||||
var request = new CreateEventRequest()
|
||||
.title("Minimal Event")
|
||||
.dateTime(OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2)))
|
||||
.timezone("UTC")
|
||||
.expiryDate(LocalDate.of(2026, 6, 16));
|
||||
.timezone("UTC");
|
||||
|
||||
var result = mockMvc.perform(post("/api/events")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
@@ -119,8 +116,7 @@ class EventControllerIntegrationTest {
|
||||
|
||||
var request = new CreateEventRequest()
|
||||
.dateTime(OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2)))
|
||||
.timezone("Europe/Berlin")
|
||||
.expiryDate(LocalDate.of(2026, 6, 16));
|
||||
.timezone("Europe/Berlin");
|
||||
|
||||
mockMvc.perform(post("/api/events")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
@@ -139,26 +135,6 @@ class EventControllerIntegrationTest {
|
||||
|
||||
var request = new CreateEventRequest()
|
||||
.title("No Date")
|
||||
.timezone("Europe/Berlin")
|
||||
.expiryDate(LocalDate.of(2026, 6, 16));
|
||||
|
||||
mockMvc.perform(post("/api/events")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(content().contentTypeCompatibleWith("application/problem+json"))
|
||||
.andExpect(jsonPath("$.fieldErrors").isArray());
|
||||
|
||||
assertThat(jpaRepository.count()).isEqualTo(countBefore);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createEventMissingExpiryDateReturns400() throws Exception {
|
||||
long countBefore = jpaRepository.count();
|
||||
|
||||
var request = new CreateEventRequest()
|
||||
.title("No Expiry")
|
||||
.dateTime(OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2)))
|
||||
.timezone("Europe/Berlin");
|
||||
|
||||
mockMvc.perform(post("/api/events")
|
||||
@@ -171,93 +147,12 @@ class EventControllerIntegrationTest {
|
||||
assertThat(jpaRepository.count()).isEqualTo(countBefore);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createEventExpiryDateInPastReturns400() throws Exception {
|
||||
long countBefore = jpaRepository.count();
|
||||
|
||||
var request = new CreateEventRequest()
|
||||
.title("Past Expiry")
|
||||
.dateTime(OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2)))
|
||||
.timezone("Europe/Berlin")
|
||||
.expiryDate(LocalDate.of(2025, 1, 1));
|
||||
|
||||
mockMvc.perform(post("/api/events")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(content().contentTypeCompatibleWith("application/problem+json"))
|
||||
.andExpect(jsonPath("$.type").value("urn:problem-type:expiry-date-in-past"));
|
||||
|
||||
assertThat(jpaRepository.count()).isEqualTo(countBefore);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createEventExpiryDateTodayReturns400() throws Exception {
|
||||
long countBefore = jpaRepository.count();
|
||||
|
||||
var request = new CreateEventRequest()
|
||||
.title("Today Expiry")
|
||||
.dateTime(OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2)))
|
||||
.timezone("Europe/Berlin")
|
||||
.expiryDate(LocalDate.now());
|
||||
|
||||
mockMvc.perform(post("/api/events")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(content().contentTypeCompatibleWith("application/problem+json"))
|
||||
.andExpect(jsonPath("$.type").value("urn:problem-type:expiry-date-in-past"));
|
||||
|
||||
assertThat(jpaRepository.count()).isEqualTo(countBefore);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createEventExpiryDateBeforeEventDateReturns400() throws Exception {
|
||||
long countBefore = jpaRepository.count();
|
||||
|
||||
var request = new CreateEventRequest()
|
||||
.title("Bad Expiry")
|
||||
.dateTime(OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2)))
|
||||
.timezone("Europe/Berlin")
|
||||
.expiryDate(LocalDate.of(2026, 6, 10));
|
||||
|
||||
mockMvc.perform(post("/api/events")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(content().contentTypeCompatibleWith("application/problem+json"))
|
||||
.andExpect(jsonPath("$.type").value("urn:problem-type:expiry-date-before-event"));
|
||||
|
||||
assertThat(jpaRepository.count()).isEqualTo(countBefore);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createEventExpiryDateSameAsEventDateReturns400() throws Exception {
|
||||
long countBefore = jpaRepository.count();
|
||||
|
||||
var request = new CreateEventRequest()
|
||||
.title("Same Day Expiry")
|
||||
.dateTime(OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2)))
|
||||
.timezone("Europe/Berlin")
|
||||
.expiryDate(LocalDate.of(2026, 6, 15));
|
||||
|
||||
mockMvc.perform(post("/api/events")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(content().contentTypeCompatibleWith("application/problem+json"))
|
||||
.andExpect(jsonPath("$.type").value("urn:problem-type:expiry-date-before-event"));
|
||||
|
||||
assertThat(jpaRepository.count()).isEqualTo(countBefore);
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorResponseContentTypeIsProblemJson() throws Exception {
|
||||
var request = new CreateEventRequest()
|
||||
.title("")
|
||||
.dateTime(OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2)))
|
||||
.timezone("Europe/Berlin")
|
||||
.expiryDate(LocalDate.of(2026, 6, 16));
|
||||
.timezone("Europe/Berlin");
|
||||
|
||||
mockMvc.perform(post("/api/events")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
@@ -273,8 +168,7 @@ class EventControllerIntegrationTest {
|
||||
var request = new CreateEventRequest()
|
||||
.title("Bad TZ")
|
||||
.dateTime(OffsetDateTime.of(2026, 6, 15, 20, 0, 0, 0, ZoneOffset.ofHours(2)))
|
||||
.timezone("Not/A/Zone")
|
||||
.expiryDate(LocalDate.of(2026, 6, 16));
|
||||
.timezone("Not/A/Zone");
|
||||
|
||||
mockMvc.perform(post("/api/events")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
@@ -302,7 +196,6 @@ class EventControllerIntegrationTest {
|
||||
.andExpect(jsonPath("$.timezone").value("Europe/Berlin"))
|
||||
.andExpect(jsonPath("$.location").value("Central Park"))
|
||||
.andExpect(jsonPath("$.attendeeCount").value(0))
|
||||
.andExpect(jsonPath("$.expired").value(false))
|
||||
.andExpect(jsonPath("$.dateTime").isNotEmpty());
|
||||
}
|
||||
|
||||
@@ -327,18 +220,6 @@ class EventControllerIntegrationTest {
|
||||
.andExpect(jsonPath("$.type").value("urn:problem-type:event-not-found"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getExpiredEventReturnsExpiredTrue() throws Exception {
|
||||
EventJpaEntity entity = seedEvent(
|
||||
"Past Event", "It happened", "Europe/Berlin",
|
||||
"Old Venue", LocalDate.now().minusDays(1));
|
||||
|
||||
mockMvc.perform(get("/api/events/" + entity.getEventToken()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.title").value("Past Event"))
|
||||
.andExpect(jsonPath("$.expired").value(true));
|
||||
}
|
||||
|
||||
// --- RSVP tests ---
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package de.fete.application.service;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -53,8 +52,7 @@ class EventServiceTest {
|
||||
"Come celebrate!",
|
||||
TODAY.plusDays(90).atStartOfDay(ZONE).toOffsetDateTime(),
|
||||
ZONE,
|
||||
"Berlin",
|
||||
TODAY.plusDays(120)
|
||||
"Berlin"
|
||||
);
|
||||
|
||||
Event result = eventService.createEvent(command);
|
||||
@@ -75,8 +73,7 @@ class EventServiceTest {
|
||||
|
||||
var command = new CreateEventCommand(
|
||||
"Test", null,
|
||||
TODAY.plusDays(10).atStartOfDay(ZONE).toOffsetDateTime(), ZONE, null,
|
||||
TODAY.plusDays(11)
|
||||
TODAY.plusDays(10).atStartOfDay(ZONE).toOffsetDateTime(), ZONE, null
|
||||
);
|
||||
|
||||
eventService.createEvent(command);
|
||||
@@ -87,86 +84,19 @@ class EventServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void expiryDateTodayThrowsException() {
|
||||
var command = new CreateEventCommand(
|
||||
"Test", null,
|
||||
TODAY.plusDays(10).atStartOfDay(ZONE).toOffsetDateTime(), ZONE, null,
|
||||
TODAY
|
||||
);
|
||||
|
||||
assertThatThrownBy(() -> eventService.createEvent(command))
|
||||
.isInstanceOf(ExpiryDateInPastException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void expiryDateInPastThrowsException() {
|
||||
var command = new CreateEventCommand(
|
||||
"Test", null,
|
||||
TODAY.plusDays(10).atStartOfDay(ZONE).toOffsetDateTime(), ZONE, null,
|
||||
TODAY.minusDays(5)
|
||||
);
|
||||
|
||||
assertThatThrownBy(() -> eventService.createEvent(command))
|
||||
.isInstanceOf(ExpiryDateInPastException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void expiryDateTomorrowSucceeds() {
|
||||
void expiryDateIsEventDatePlusSevenDays() {
|
||||
when(eventRepository.save(any(Event.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
var eventDate = TODAY.plusDays(10);
|
||||
var command = new CreateEventCommand(
|
||||
"Test", null,
|
||||
TODAY.plusDays(1).atStartOfDay(ZONE).toOffsetDateTime(), ZONE, null,
|
||||
TODAY.plusDays(2)
|
||||
eventDate.atStartOfDay(ZONE).toOffsetDateTime(), ZONE, null
|
||||
);
|
||||
|
||||
Event result = eventService.createEvent(command);
|
||||
|
||||
assertThat(result.getExpiryDate()).isEqualTo(TODAY.plusDays(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void expiryDateSameAsEventDateThrowsException() {
|
||||
var command = new CreateEventCommand(
|
||||
"Test", null,
|
||||
TODAY.plusDays(10).atStartOfDay(ZONE).toOffsetDateTime(),
|
||||
ZONE, null,
|
||||
TODAY.plusDays(10)
|
||||
);
|
||||
|
||||
assertThatThrownBy(() -> eventService.createEvent(command))
|
||||
.isInstanceOf(ExpiryDateBeforeEventException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void expiryDateBeforeEventDateThrowsException() {
|
||||
var command = new CreateEventCommand(
|
||||
"Test", null,
|
||||
TODAY.plusDays(10).atStartOfDay(ZONE).toOffsetDateTime(),
|
||||
ZONE, null,
|
||||
TODAY.plusDays(5)
|
||||
);
|
||||
|
||||
assertThatThrownBy(() -> eventService.createEvent(command))
|
||||
.isInstanceOf(ExpiryDateBeforeEventException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void expiryDateDayAfterEventDateSucceeds() {
|
||||
when(eventRepository.save(any(Event.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
var command = new CreateEventCommand(
|
||||
"Test", null,
|
||||
TODAY.plusDays(10).atStartOfDay(ZONE).toOffsetDateTime(),
|
||||
ZONE, null,
|
||||
TODAY.plusDays(11)
|
||||
);
|
||||
|
||||
Event result = eventService.createEvent(command);
|
||||
|
||||
assertThat(result.getExpiryDate()).isEqualTo(TODAY.plusDays(11));
|
||||
assertThat(result.getExpiryDate()).isEqualTo(eventDate.plusDays(7));
|
||||
}
|
||||
|
||||
// --- GetEventUseCase tests (T004) ---
|
||||
@@ -207,8 +137,7 @@ class EventServiceTest {
|
||||
var command = new CreateEventCommand(
|
||||
"Test", null,
|
||||
TODAY.plusDays(10).atStartOfDay(ZONE).toOffsetDateTime(),
|
||||
ZoneId.of("America/New_York"), null,
|
||||
TODAY.plusDays(11)
|
||||
ZoneId.of("America/New_York"), null
|
||||
);
|
||||
|
||||
Event result = eventService.createEvent(command);
|
||||
|
||||
Reference in New Issue
Block a user