Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public record TripDTO(
@JsonProperty("thumbnailUrl")
public String thumbnailUrl() {
boolean hasUpdates = updateCount != null && updateCount > 0;
return ThumbnailUrlService.resolveTripThumbnailUrl(id, hasUpdates, tripPlanId);
Long timestamp = polylineUpdatedAt != null ? polylineUpdatedAt.getEpochSecond() : null;
return ThumbnailUrlService.resolveTripThumbnailUrl(id, hasUpdates, tripPlanId, timestamp);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ public record TripSummaryDTO(
Boolean isPromoted,
Instant promotedAt,
Boolean isPreAnnounced,
Instant countdownStartDate) {
Instant countdownStartDate,
Instant polylineUpdatedAt) { // For cache-busting

@JsonProperty("thumbnailUrl")
public String thumbnailUrl() {
boolean hasUpdates = updateCount != null && updateCount > 0;
return ThumbnailUrlService.resolveTripThumbnailUrl(id, hasUpdates, tripPlanId);
Long timestamp = polylineUpdatedAt != null ? polylineUpdatedAt.getEpochSecond() : null;
return ThumbnailUrlService.resolveTripThumbnailUrl(id, hasUpdates, tripPlanId, timestamp);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,47 @@ public static String generateTripPlanThumbnailUrl(UUID tripPlanId) {
/**
* Resolves the appropriate thumbnail URL for a trip. If the trip has no updates but has a trip
* plan, falls back to the plan thumbnail. Otherwise uses the trip thumbnail.
* Includes a cache-busting query parameter based on the polyline update timestamp.
*
* @param tripId the trip ID (as String)
* @param hasUpdates whether the trip has any updates/locations
* @param tripPlanId the trip plan ID (as String), may be null
* @return the resolved thumbnail URL, or null if tripId is null
* @param polylineUpdatedAt the timestamp when polyline was last updated, used for cache busting
* @return the resolved thumbnail URL with cache-busting parameter, or null if tripId is null
*/
public static String resolveTripThumbnailUrl(
String tripId, boolean hasUpdates, String tripPlanId) {
String tripId, boolean hasUpdates, String tripPlanId, Long polylineUpdatedAt) {
if (tripId == null) {
return null;
}
String baseUrl;
if (!hasUpdates && tripPlanId != null && !tripPlanId.isEmpty()) {
return generateTripPlanThumbnailUrl(UUID.fromString(tripPlanId));
baseUrl = generateTripPlanThumbnailUrl(UUID.fromString(tripPlanId));
} else {
baseUrl = generateTripThumbnailUrl(UUID.fromString(tripId));
}
return generateTripThumbnailUrl(UUID.fromString(tripId));

// Add cache-busting parameter if polylineUpdatedAt is available
if (polylineUpdatedAt != null && polylineUpdatedAt > 0) {
return baseUrl + "?v=" + polylineUpdatedAt;
}
return baseUrl;
}

/**
* Resolves the appropriate thumbnail URL for a trip without cache-busting.
* Kept for backward compatibility.
*
* @param tripId the trip ID (as String)
* @param hasUpdates whether the trip has any updates/locations
* @param tripPlanId the trip plan ID (as String), may be null
* @return the resolved thumbnail URL, or null if tripId is null
* @deprecated Use {@link #resolveTripThumbnailUrl(String, boolean, String, Long)} instead
*/
@Deprecated
public static String resolveTripThumbnailUrl(
String tripId, boolean hasUpdates, String tripPlanId) {
return resolveTripThumbnailUrl(tripId, hasUpdates, tripPlanId, null);
}

public static String generateUserProfileThumbnailUrl(UUID userId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ void generateUserProfileThumbnailUrl_shouldReturnNull_whenNull() {

@Test
void resolveTripThumbnailUrl_shouldReturnNull_whenTripIdIsNull() {
assertNull(ThumbnailUrlService.resolveTripThumbnailUrl(null, true, null));
assertNull(ThumbnailUrlService.resolveTripThumbnailUrl(null, true, null, null));
}

@Test
Expand All @@ -104,7 +104,7 @@ void resolveTripThumbnailUrl_shouldReturnTripThumbnail_whenHasUpdates() {

String result =
ThumbnailUrlService.resolveTripThumbnailUrl(
tripId.toString(), true, planId.toString());
tripId.toString(), true, planId.toString(), null);

assertEquals("/thumbnails/trips/" + tripId + ".png", result);
}
Expand All @@ -116,7 +116,7 @@ void resolveTripThumbnailUrl_shouldReturnPlanThumbnail_whenNoUpdatesAndHasPlan()

String result =
ThumbnailUrlService.resolveTripThumbnailUrl(
tripId.toString(), false, planId.toString());
tripId.toString(), false, planId.toString(), null);

assertEquals("/thumbnails/plans/" + planId + ".png", result);
}
Expand All @@ -126,7 +126,7 @@ void resolveTripThumbnailUrl_shouldReturnTripThumbnail_whenNoUpdatesAndNoPlan()
UUID tripId = UUID.randomUUID();

String result =
ThumbnailUrlService.resolveTripThumbnailUrl(tripId.toString(), false, null);
ThumbnailUrlService.resolveTripThumbnailUrl(tripId.toString(), false, null, null);

assertEquals("/thumbnails/trips/" + tripId + ".png", result);
}
Expand All @@ -135,7 +135,7 @@ void resolveTripThumbnailUrl_shouldReturnTripThumbnail_whenNoUpdatesAndNoPlan()
void resolveTripThumbnailUrl_shouldReturnTripThumbnail_whenNoUpdatesAndEmptyPlanId() {
UUID tripId = UUID.randomUUID();

String result = ThumbnailUrlService.resolveTripThumbnailUrl(tripId.toString(), false, "");
String result = ThumbnailUrlService.resolveTripThumbnailUrl(tripId.toString(), false, "", null);

assertEquals("/thumbnails/trips/" + tripId + ".png", result);
}
Expand All @@ -145,7 +145,7 @@ void resolveTripThumbnailUrl_shouldReturnTripThumbnail_whenHasUpdatesAndNoPlan()
UUID tripId = UUID.randomUUID();

String result =
ThumbnailUrlService.resolveTripThumbnailUrl(tripId.toString(), true, null);
ThumbnailUrlService.resolveTripThumbnailUrl(tripId.toString(), true, null, null);

assertEquals("/thumbnails/trips/" + tripId + ".png", result);
}
Expand All @@ -158,9 +158,56 @@ void resolveTripThumbnailUrl_shouldPreferTripThumbnail_whenHasUpdatesEvenWithPla
// Even though a plan exists, having updates means we use the trip thumbnail
String result =
ThumbnailUrlService.resolveTripThumbnailUrl(
tripId.toString(), true, planId.toString());
tripId.toString(), true, planId.toString(), null);

assertEquals("/thumbnails/trips/" + tripId + ".png", result);
}

@Test
void resolveTripThumbnailUrl_shouldIncludeCacheBustingParameter_whenTimestampProvided() {
UUID tripId = UUID.randomUUID();
Long timestamp = 1234567890L;

String result =
ThumbnailUrlService.resolveTripThumbnailUrl(
tripId.toString(), true, null, timestamp);

assertEquals("/thumbnails/trips/" + tripId + ".png?v=" + timestamp, result);
}

@Test
void resolveTripThumbnailUrl_shouldNotIncludeCacheBustingParameter_whenTimestampIsNull() {
UUID tripId = UUID.randomUUID();

String result =
ThumbnailUrlService.resolveTripThumbnailUrl(
tripId.toString(), true, null, null);

assertEquals("/thumbnails/trips/" + tripId + ".png", result);
}

@Test
void resolveTripThumbnailUrl_shouldNotIncludeCacheBustingParameter_whenTimestampIsZero() {
UUID tripId = UUID.randomUUID();

String result =
ThumbnailUrlService.resolveTripThumbnailUrl(
tripId.toString(), true, null, 0L);

assertEquals("/thumbnails/trips/" + tripId + ".png", result);
}

@Test
void resolveTripThumbnailUrl_shouldIncludeCacheBustingOnPlanThumbnail_whenTimestampProvided() {
UUID tripId = UUID.randomUUID();
UUID planId = UUID.randomUUID();
Long timestamp = 9876543210L;

String result =
ThumbnailUrlService.resolveTripThumbnailUrl(
tripId.toString(), false, planId.toString(), timestamp);

assertEquals("/thumbnails/plans/" + planId + ".png?v=" + timestamp, result);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ public static TripSummaryDTO toTripSummaryDTO(
isPromoted,
promotedInfo != null ? promotedInfo.getPromotedAt() : null,
promotedInfo != null && promotedInfo.isPreAnnounced(),
promotedInfo != null ? promotedInfo.getCountdownStartDate() : null);
promotedInfo != null ? promotedInfo.getCountdownStartDate() : null,
trip.getPolylineUpdatedAt()); // For cache-busting
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ private TripSummaryDTO createTripSummaryDTOWithStatus(
Boolean.FALSE, // isPromoted
null, // promotedAt
Boolean.FALSE, // isPreAnnounced
null); // countdownStartDate
null, // countdownStartDate
null); // polylineUpdatedAt
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,8 @@ private TripSummaryDTO createTripSummaryDTO(UUID tripId, UUID userId, String nam
false, // isPromoted
null, // promotedAt
false, // isPreAnnounced
null); // countdownStartDate
null, // countdownStartDate
null); // polylineUpdatedAt
}

private TripSummaryDTO createPromotedTripSummaryDTO(
Expand All @@ -518,7 +519,8 @@ private TripSummaryDTO createPromotedTripSummaryDTO(
true, // isPromoted
promotedAt,
false, // isPreAnnounced
null); // countdownStartDate
null, // countdownStartDate
null); // polylineUpdatedAt
}

private UserSummaryDto createUserSummary(UUID id, String username, String displayName) {
Expand Down
Loading