From 9c3eba8c9717634f5f93164ee3c287a2185f31d3 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 22 Nov 2024 16:59:10 -0500 Subject: [PATCH] Resolve conflicts --- .../api/MonitoredTripController.java | 88 +++++++++++++++++++ .../middleware/models/MonitoredTrip.java | 13 +++ .../tripmonitor/jobs/CheckMonitoredTrip.java | 8 +- 3 files changed, 102 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/opentripplanner/middleware/controllers/api/MonitoredTripController.java b/src/main/java/org/opentripplanner/middleware/controllers/api/MonitoredTripController.java index 49b854425..d643c4096 100644 --- a/src/main/java/org/opentripplanner/middleware/controllers/api/MonitoredTripController.java +++ b/src/main/java/org/opentripplanner/middleware/controllers/api/MonitoredTripController.java @@ -5,26 +5,37 @@ import com.mongodb.client.model.Filters; import org.bson.conversions.Bson; import org.eclipse.jetty.http.HttpStatus; +import org.opentripplanner.middleware.i18n.Message; import org.opentripplanner.middleware.models.ItineraryExistence; import org.opentripplanner.middleware.models.MonitoredTrip; import org.opentripplanner.middleware.models.OtpUser; import org.opentripplanner.middleware.persistence.Persistence; +import org.opentripplanner.middleware.models.RelatedUser; import org.opentripplanner.middleware.tripmonitor.jobs.CheckMonitoredTrip; import org.opentripplanner.middleware.tripmonitor.jobs.MonitoredTripLocks; +import org.opentripplanner.middleware.utils.ConfigUtils; import org.opentripplanner.middleware.utils.InvalidItineraryReason; import org.opentripplanner.middleware.utils.JsonUtils; +import org.opentripplanner.middleware.utils.NotificationUtils; import org.opentripplanner.middleware.utils.SwaggerUtils; import spark.Request; import spark.Response; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import static io.github.manusant.ss.descriptor.MethodDescriptor.path; import static com.mongodb.client.model.Filters.eq; import static org.opentripplanner.middleware.models.MonitoredTrip.USER_ID_FIELD_NAME; +import static org.opentripplanner.middleware.tripmonitor.jobs.CheckMonitoredTrip.SETTINGS_PATH; import static org.opentripplanner.middleware.utils.ConfigUtils.getConfigPropertyAsInt; import static org.opentripplanner.middleware.utils.HttpUtils.JSON_ONLY; +import static org.opentripplanner.middleware.utils.I18nUtils.getOtpUserLocale; +import static org.opentripplanner.middleware.utils.I18nUtils.label; import static org.opentripplanner.middleware.utils.JsonUtils.getPOJOFromRequestBody; import static org.opentripplanner.middleware.utils.JsonUtils.logMessageAndHalt; @@ -36,6 +47,10 @@ public class MonitoredTripController extends ApiController { private static final int MAXIMUM_PERMITTED_MONITORED_TRIPS = getConfigPropertyAsInt("MAXIMUM_PERMITTED_MONITORED_TRIPS", 5); + private final String OTP_UI_NAME = ConfigUtils.getConfigPropertyAsText("OTP_UI_NAME"); + + private static final String OTP_UI_URL = ConfigUtils.getConfigPropertyAsText("OTP_UI_URL"); + public MonitoredTripController(String apiPrefix) { super(apiPrefix, Persistence.monitoredTrips, "secure/monitoredtrip"); } @@ -90,6 +105,8 @@ MonitoredTrip preCreateHook(MonitoredTrip monitoredTrip, Request req) { } } + notifyTripCompanionsAndObservers(monitoredTrip, null); + return monitoredTrip; } @@ -128,6 +145,74 @@ private void preCreateOrUpdateChecks(MonitoredTrip monitoredTrip, Request req) { processTripQueryParams(monitoredTrip, req); } + /** Notify users added as companions or observers to a trip. (Removed users won't get notified.) */ + private void notifyTripCompanionsAndObservers(MonitoredTrip monitoredTrip, MonitoredTrip originalTrip) { + RelatedUser addedCompanion = null; + List addedObservers = new ArrayList<>(); + if (monitoredTrip.companion != null) { + if (originalTrip == null || originalTrip.companion == null) { + // notify everyone + addedCompanion = monitoredTrip.companion; + } else { + // notify added companions + if (!originalTrip.companion.email.equals(monitoredTrip.companion.email)) { + addedCompanion = monitoredTrip.companion; + } + } + } + + if (monitoredTrip.observers != null) { + if (originalTrip == null || originalTrip.observers == null) { + // notify everyone + addedObservers.addAll(monitoredTrip.observers); + } else { + // notify added observers + Set existingObserverEmails = originalTrip.observers.stream() + .map(obs -> obs.email) + .collect(Collectors.toSet()); + monitoredTrip.observers.forEach(obs -> { + if (!existingObserverEmails.contains(obs.email)) { + addedObservers.add(obs); + } + }); + } + } + + if (addedCompanion != null) { + OtpUser companionUser = Persistence.otpUsers.getOneFiltered(Filters.eq("email", addedCompanion.email)); + if (companionUser != null) { + Locale locale = getOtpUserLocale(companionUser); + String tripLinkLabel = Message.TRIP_LINK_TEXT.get(locale); + String tripUrl = monitoredTrip.getTripUrl(); + + OtpUser tripCreator = Persistence.otpUsers.getById(monitoredTrip.userId); + + // TODO: finish i18n + // TODO: Refactor common email data. + NotificationUtils.sendEmail( + companionUser, + String.format("%s: %s shared a trip with you.", OTP_UI_NAME, tripCreator.email), + "ShareTripText.ftl", + "ShareTripHtml.ftl", + Map.of( + "emailGreeting", String.format( + "You are a companion for %s on a trip from %s to %s.", + tripCreator.email, + monitoredTrip.from.name, + monitoredTrip.to.name + ), + "tripUrl", tripUrl, + "tripLinkAnchorLabel", tripLinkLabel, + "tripLinkLabelAndUrl", label(tripLinkLabel, tripUrl, locale), + "emailFooter", String.format(Message.TRIP_EMAIL_FOOTER.get(locale), OTP_UI_NAME), + "manageLinkText", Message.TRIP_EMAIL_MANAGE_NOTIFICATIONS.get(locale), + "manageLinkUrl", String.format("%s%s", OTP_UI_URL, SETTINGS_PATH) + ) + ); + } + } + } + /** * Processes the {@link MonitoredTrip} query parameters, so the trip's fields match the query parameters. * If an error occurs regarding the query params, returns a HTTP 400 status. @@ -171,6 +256,9 @@ MonitoredTrip preUpdateHook(MonitoredTrip monitoredTrip, MonitoredTrip preExisti // perform the database update here before releasing the lock to be sure that the record is updated in the // database before a CheckMonitoredTripJob analyzes the data Persistence.monitoredTrips.replace(monitoredTrip.id, monitoredTrip); + + notifyTripCompanionsAndObservers(monitoredTrip, preExisting); + return runCheckMonitoredTrip(monitoredTrip); } catch (Exception e) { // FIXME: an error happened while updating the trip, but the trip might have been saved to the DB, so return diff --git a/src/main/java/org/opentripplanner/middleware/models/MonitoredTrip.java b/src/main/java/org/opentripplanner/middleware/models/MonitoredTrip.java index 1626ca8fd..da946c7f0 100644 --- a/src/main/java/org/opentripplanner/middleware/models/MonitoredTrip.java +++ b/src/main/java/org/opentripplanner/middleware/models/MonitoredTrip.java @@ -17,6 +17,7 @@ import org.opentripplanner.middleware.persistence.Persistence; import org.opentripplanner.middleware.persistence.TypedPersistence; import org.opentripplanner.middleware.tripmonitor.JourneyState; +import org.opentripplanner.middleware.utils.ConfigUtils; import org.opentripplanner.middleware.utils.DateTimeUtils; import org.opentripplanner.middleware.utils.ItineraryUtils; import spark.Request; @@ -29,6 +30,8 @@ import java.util.List; import java.util.function.Function; +import static org.opentripplanner.middleware.tripmonitor.jobs.CheckMonitoredTrip.ACCOUNT_PATH; + /** * A monitored trip represents a trip a user would like to receive notification on if affected by a delay and/or route * change. @@ -38,6 +41,10 @@ public class MonitoredTrip extends Model { public static final String USER_ID_FIELD_NAME = "userId"; + private final String TRIPS_PATH = ACCOUNT_PATH + "/trips"; + + private static final String OTP_UI_URL = ConfigUtils.getConfigPropertyAsText("OTP_UI_URL"); + /** * Mongo Id of the {@link OtpUser} who owns this monitored trip. */ @@ -427,4 +434,10 @@ public int tripTimeMinute() { public boolean isOneTime() { return !monday && !tuesday && !wednesday && !thursday && !friday && !saturday && !sunday; } + + @JsonIgnore + @BsonIgnore + public String getTripUrl() { + return String.format("%s%s/%s", OTP_UI_URL, TRIPS_PATH, id); + } } diff --git a/src/main/java/org/opentripplanner/middleware/tripmonitor/jobs/CheckMonitoredTrip.java b/src/main/java/org/opentripplanner/middleware/tripmonitor/jobs/CheckMonitoredTrip.java index d8c44769f..a2be9347e 100644 --- a/src/main/java/org/opentripplanner/middleware/tripmonitor/jobs/CheckMonitoredTrip.java +++ b/src/main/java/org/opentripplanner/middleware/tripmonitor/jobs/CheckMonitoredTrip.java @@ -59,8 +59,6 @@ public class CheckMonitoredTrip implements Runnable { public static final String ACCOUNT_PATH = "/#/account"; - private final String TRIPS_PATH = ACCOUNT_PATH + "/trips"; - public static final String SETTINGS_PATH = ACCOUNT_PATH + "/settings"; public final MonitoredTrip trip; @@ -530,7 +528,7 @@ private void sendNotifications() { Locale locale = getOtpUserLocale(); String tripLinkLabel = Message.TRIP_LINK_TEXT.get(locale); - String tripUrl = getTripUrl(); + String tripUrl = trip.getTripUrl(); // A HashMap is needed instead of a Map for template data to be serialized to the template renderer. Map templateData = new HashMap<>(Map.of( "emailGreeting", Message.TRIP_EMAIL_GREETING.get(locale), @@ -925,8 +923,4 @@ private OtpUser getOtpUser() { private Locale getOtpUserLocale() { return I18nUtils.getOtpUserLocale(getOtpUser()); } - - private String getTripUrl() { - return String.format("%s%s/%s", OTP_UI_URL, TRIPS_PATH, trip.id); - } }