From 2c2d7d9fcc96273cff22249054cec8aa7e703739 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 12 Dec 2024 12:43:58 -0500 Subject: [PATCH 1/7] feat(TripSurveyController): Add redirect endpoint for surveys. --- .../middleware/OtpMiddlewareMain.java | 2 + .../controllers/api/TripSurveyController.java | 90 +++++++++++++++++++ .../middleware/utils/NotificationUtils.java | 4 +- .../api/TripSurveyControllerTest.java | 15 ++++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java create mode 100644 src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java diff --git a/src/main/java/org/opentripplanner/middleware/OtpMiddlewareMain.java b/src/main/java/org/opentripplanner/middleware/OtpMiddlewareMain.java index a15523d3b..3b34d3bc2 100644 --- a/src/main/java/org/opentripplanner/middleware/OtpMiddlewareMain.java +++ b/src/main/java/org/opentripplanner/middleware/OtpMiddlewareMain.java @@ -18,6 +18,7 @@ import org.opentripplanner.middleware.controllers.api.OtpUserController; import org.opentripplanner.middleware.controllers.api.TrackedTripController; import org.opentripplanner.middleware.controllers.api.TripHistoryController; +import org.opentripplanner.middleware.controllers.api.TripSurveyController; import org.opentripplanner.middleware.docs.PublicApiDocGenerator; import org.opentripplanner.middleware.models.MonitoredComponent; import org.opentripplanner.middleware.otp.OtpVersion; @@ -129,6 +130,7 @@ private static void initializeHttpEndpoints() throws IOException { new LogController(API_PREFIX), new ErrorEventsController(API_PREFIX), new CDPFilesController(API_PREFIX), + new TripSurveyController(API_PREFIX), new OtpRequestProcessor("/otp", OtpVersion.OTP2), new OtpRequestProcessor("/otp2", OtpVersion.OTP2) // Add other endpoints as needed. diff --git a/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java b/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java new file mode 100644 index 000000000..6405046f8 --- /dev/null +++ b/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java @@ -0,0 +1,90 @@ +package org.opentripplanner.middleware.controllers.api; + +import io.github.manusant.ss.SparkSwagger; +import io.github.manusant.ss.rest.Endpoint; +import org.opentripplanner.middleware.utils.HttpUtils; +import org.opentripplanner.middleware.utils.JsonUtils; +import spark.Request; +import spark.Response; + +import static io.github.manusant.ss.descriptor.EndpointDescriptor.endpointPath; +import static io.github.manusant.ss.descriptor.MethodDescriptor.path; +import static org.opentripplanner.middleware.utils.NotificationUtils.TRIP_SURVEY_ID; +import static org.opentripplanner.middleware.utils.NotificationUtils.TRIP_SURVEY_SUBDOMAIN; + +public class TripSurveyController implements Endpoint { + private final String ROOT_ROUTE; + + private static final String OPEN_PATH = "/open"; + + public TripSurveyController(String apiPrefix) { + this.ROOT_ROUTE = apiPrefix + "trip-survey"; + } + + /** + * Register the API endpoint and GET resource that redirects to a survey form. + */ + @Override + public void bind(final SparkSwagger restApi) { + restApi.endpoint( + endpointPath(ROOT_ROUTE).withDescription("Interface for tracking opened trip surveys following a trip survey notification"), + HttpUtils.NO_FILTER + ) + .get( + path(ROOT_ROUTE + OPEN_PATH) + .withDescription("Generates a tracking survey link for a specified user, trip, notification ids.") + .withQueryParam().withName("user_id").withRequired(true).withDescription("The id of the OtpUser that this notification applies to.").and() + .withQueryParam().withName("trip_id").withRequired(true).withDescription("The id of the MonitoredTrip that this notification applies to.").and() + .withQueryParam().withName("notification_id").withRequired(true).withDescription("The id of the notification that this notification applies to.").and(), + TripSurveyController::processCall, JsonUtils::toJson + ); + } + + /** + * Check that the requested survey is valid (user, trip, and notifications point to existing data). + */ + private static void checkParameters(Request req, Response res) { + // TODO + + } + + /** + * Mark notification as opened. + */ + private static void updateNotificationState(Response res) { + // TODO + + } + + public static String makeTripSurveyUrl(String subdomain, String surveyId, String userId, String tripId, String notificationId) { + // Parameters have been checked before, so there shouldn't be a need to encode parameters. + return String.format( + "https://%s.typeform.com/to/%s#user_id=%s&trip_id=%s¬ification_id=%s", + subdomain, + surveyId, + userId, + tripId, + notificationId + ); + } + + private static boolean processCall(Request req, Response res) { + checkParameters(req, res); + + String surveyUrl = makeTripSurveyUrl( + TRIP_SURVEY_SUBDOMAIN, + TRIP_SURVEY_ID, + req.queryParams("user_id"), + req.queryParams("trip_id"), + req.queryParams("notification_id") + ); + + // Update notification state + updateNotificationState(res); + + // Redirect + res.redirect(surveyUrl); + + return true; + } +} diff --git a/src/main/java/org/opentripplanner/middleware/utils/NotificationUtils.java b/src/main/java/org/opentripplanner/middleware/utils/NotificationUtils.java index 251f39240..265790f21 100644 --- a/src/main/java/org/opentripplanner/middleware/utils/NotificationUtils.java +++ b/src/main/java/org/opentripplanner/middleware/utils/NotificationUtils.java @@ -64,8 +64,8 @@ public class NotificationUtils { public static final String OTP_ADMIN_DASHBOARD_FROM_EMAIL = getConfigPropertyAsText("OTP_ADMIN_DASHBOARD_FROM_EMAIL"); private static final String PUSH_API_KEY = getConfigPropertyAsText("PUSH_API_KEY"); private static final String PUSH_API_URL = getConfigPropertyAsText("PUSH_API_URL"); - private static final String TRIP_SURVEY_ID = getConfigPropertyAsText("TRIP_SURVEY_ID"); - private static final String TRIP_SURVEY_SUBDOMAIN = getConfigPropertyAsText("TRIP_SURVEY_SUBDOMAIN"); + public static final String TRIP_SURVEY_ID = getConfigPropertyAsText("TRIP_SURVEY_ID"); + public static final String TRIP_SURVEY_SUBDOMAIN = getConfigPropertyAsText("TRIP_SURVEY_SUBDOMAIN"); private static final String OTP_UI_NAME = ConfigUtils.getConfigPropertyAsText("OTP_UI_NAME"); private static final String OTP_UI_URL = ConfigUtils.getConfigPropertyAsText("OTP_UI_URL"); private static final String TRIPS_PATH = ACCOUNT_PATH + "/trips"; diff --git a/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java b/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java new file mode 100644 index 000000000..fa43dc481 --- /dev/null +++ b/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java @@ -0,0 +1,15 @@ +package org.opentripplanner.middleware.controllers.api; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class TripSurveyControllerTest { + @Test + void canMakeTripSurveyUrl() { + assertEquals( + "https://subdomain.typeform.com/to/survey-1#user_id=user-2&trip_id=trip-3¬ification_id=notif-4", + TripSurveyController.makeTripSurveyUrl("subdomain", "survey-1", "user-2", "trip-3", "notif-4") + ); + } +} From 81bb4c47cf0e8e0c40a3bbd436c03815ed608c07 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:11:41 -0500 Subject: [PATCH 2/7] feat(TripSurveyController): Update notification state after processing call. --- .../controllers/api/TripSurveyController.java | 57 ++++++---- .../models/TripSurveyNotification.java | 4 +- .../api/TripSurveyControllerTest.java | 106 +++++++++++++++++- 3 files changed, 146 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java b/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java index 6405046f8..7541b352c 100644 --- a/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java +++ b/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java @@ -2,11 +2,17 @@ import io.github.manusant.ss.SparkSwagger; import io.github.manusant.ss.rest.Endpoint; +import org.opentripplanner.middleware.models.OtpUser; +import org.opentripplanner.middleware.models.TripSurveyNotification; +import org.opentripplanner.middleware.persistence.Persistence; import org.opentripplanner.middleware.utils.HttpUtils; import org.opentripplanner.middleware.utils.JsonUtils; import spark.Request; import spark.Response; +import java.time.Instant; +import java.util.Date; + import static io.github.manusant.ss.descriptor.EndpointDescriptor.endpointPath; import static io.github.manusant.ss.descriptor.MethodDescriptor.path; import static org.opentripplanner.middleware.utils.NotificationUtils.TRIP_SURVEY_ID; @@ -43,17 +49,22 @@ public void bind(final SparkSwagger restApi) { /** * Check that the requested survey is valid (user, trip, and notifications point to existing data). */ - private static void checkParameters(Request req, Response res) { + private static OtpUser checkParameters(String userId, String tripId, String notificationId, Response res) { // TODO - + return Persistence.otpUsers.getById(userId); } /** * Mark notification as opened. */ - private static void updateNotificationState(Response res) { - // TODO - + private static void updateNotificationState(OtpUser user, String notificationId) { + for (TripSurveyNotification notification : user.tripSurveyNotifications) { + if (notificationId.equals(notification.id)) { + notification.timeOpened = Date.from(Instant.now()); + break; + } + } + Persistence.otpUsers.replace(user.id, user); } public static String makeTripSurveyUrl(String subdomain, String surveyId, String userId, String tripId, String notificationId) { @@ -69,22 +80,30 @@ public static String makeTripSurveyUrl(String subdomain, String surveyId, String } private static boolean processCall(Request req, Response res) { - checkParameters(req, res); - - String surveyUrl = makeTripSurveyUrl( - TRIP_SURVEY_SUBDOMAIN, - TRIP_SURVEY_ID, - req.queryParams("user_id"), - req.queryParams("trip_id"), - req.queryParams("notification_id") - ); + String userId = req.queryParams("user_id"); + String tripId = req.queryParams("trip_id"); + String notificationId = req.queryParams("notification_id"); + + OtpUser user = checkParameters(userId, tripId, notificationId, res); + + if (user != null) { + String surveyUrl = makeTripSurveyUrl( + TRIP_SURVEY_SUBDOMAIN, + TRIP_SURVEY_ID, + userId, + tripId, + notificationId + ); + + // Update notification state + updateNotificationState(user, notificationId); - // Update notification state - updateNotificationState(res); + // Redirect + res.redirect(surveyUrl); - // Redirect - res.redirect(surveyUrl); + return true; + } - return true; + return false; } } diff --git a/src/main/java/org/opentripplanner/middleware/models/TripSurveyNotification.java b/src/main/java/org/opentripplanner/middleware/models/TripSurveyNotification.java index 0d6ec8af0..bb6d7f621 100644 --- a/src/main/java/org/opentripplanner/middleware/models/TripSurveyNotification.java +++ b/src/main/java/org/opentripplanner/middleware/models/TripSurveyNotification.java @@ -1,7 +1,6 @@ package org.opentripplanner.middleware.models; import java.util.Date; -import java.util.UUID; /** Contains information regarding survey notifications sent after a trip is completed. */ public class TripSurveyNotification { @@ -17,6 +16,9 @@ public class TripSurveyNotification { /** Date/time when the trip survey notification was sent. */ public Date timeSent; + /** Date/time when the trip survey notification was opened. */ + public Date timeOpened; + /** The {@link TrackedJourney} (and, indirectly, the {@link MonitoredTrip}) that this notification refers to. */ public String journeyId; diff --git a/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java b/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java index fa43dc481..352f28568 100644 --- a/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java +++ b/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java @@ -1,10 +1,74 @@ package org.opentripplanner.middleware.controllers.api; +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.opentripplanner.middleware.models.MonitoredTrip; +import org.opentripplanner.middleware.models.OtpUser; +import org.opentripplanner.middleware.models.TrackedJourney; +import org.opentripplanner.middleware.models.TripSurveyNotification; +import org.opentripplanner.middleware.persistence.Persistence; +import org.opentripplanner.middleware.testutils.ApiTestUtils; +import org.opentripplanner.middleware.testutils.OtpMiddlewareTestEnvironment; +import org.opentripplanner.middleware.testutils.PersistenceTestUtils; + +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; +import static org.opentripplanner.middleware.testutils.ApiTestUtils.makeRequest; + +class TripSurveyControllerTest extends OtpMiddlewareTestEnvironment { + private static OtpUser otpUser; + private static MonitoredTrip monitoredTrip; + private static TrackedJourney trackedJourney; + private static final String NOTIFICATION_ID = UUID.randomUUID().toString(); + + @BeforeAll + public static void setUp() throws Exception { + assumeTrue(IS_END_TO_END); + otpUser = PersistenceTestUtils.createUser(ApiTestUtils.generateEmailAddress("test-otpuser")); + monitoredTrip = createMonitoredTrip(); + + trackedJourney = new TrackedJourney(); + trackedJourney.id = UUID.randomUUID().toString(); + Persistence.trackedJourneys.create(trackedJourney); + + otpUser.tripSurveyNotifications = List.of( + new TripSurveyNotification("other-notification", Date.from(Instant.now()), "other-journey"), + new TripSurveyNotification(NOTIFICATION_ID, Date.from(Instant.now()), trackedJourney.id) + ); + Persistence.otpUsers.replace(otpUser.id, otpUser); + } + + private static MonitoredTrip createMonitoredTrip() { + MonitoredTrip trip = new MonitoredTrip(); + trip.id = UUID.randomUUID().toString(); + trip.userId = otpUser.id; + Persistence.monitoredTrips.create(trip); + return trip; + } + + @AfterAll + public static void tearDown() throws Exception { + assumeTrue(IS_END_TO_END); + otpUser = Persistence.otpUsers.getById(otpUser.id); + if (otpUser != null) otpUser.delete(true); + monitoredTrip = Persistence.monitoredTrips.getById(monitoredTrip.id); + if (monitoredTrip != null) monitoredTrip.delete(); + trackedJourney = Persistence.trackedJourneys.getById(trackedJourney.id); + if (trackedJourney != null) trackedJourney.delete(); + } -class TripSurveyControllerTest { @Test void canMakeTripSurveyUrl() { assertEquals( @@ -12,4 +76,44 @@ void canMakeTripSurveyUrl() { TripSurveyController.makeTripSurveyUrl("subdomain", "survey-1", "user-2", "trip-3", "notif-4") ); } + + @Test + void canOpenSurveyAndUpdateNotificationStatus() { + assumeTrue(IS_END_TO_END); + + OtpUser existingUser = Persistence.otpUsers.getById(otpUser.id); + assertNotNull(existingUser); + existingUser.tripSurveyNotifications.forEach(n -> { + assertNull(n.timeOpened); + }); + + Instant requestInstant = Instant.now(); + var response = makeRequest( + String.format( + "api/trip-survey/open?user_id=%s&trip_id=%s¬ification_id=%s", + otpUser.id, + monitoredTrip.id, + NOTIFICATION_ID + ), + "", + Map.of(), + HttpMethod.GET + ); + Instant requestCompleteInstant = Instant.now(); + + assertEquals(HttpStatus.OK_200, response.status); + + OtpUser updatedUser = Persistence.otpUsers.getById(otpUser.id); + assertNotNull(updatedUser); + assertEquals(otpUser.tripSurveyNotifications.size(), updatedUser.tripSurveyNotifications.size()); + updatedUser.tripSurveyNotifications.forEach(n -> { + if (NOTIFICATION_ID.equals(n.id)) { + assertNotNull(n.timeOpened); + assertTrue(n.timeOpened.toInstant().isAfter(requestInstant)); + assertTrue(n.timeOpened.toInstant().isBefore(requestCompleteInstant)); + } else { + assertNull(n.timeOpened); + } + }); + } } From 31c77b7021bc73c9856b96fae2b761ee52598b4c Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 12 Dec 2024 18:38:33 -0500 Subject: [PATCH 3/7] refactor(TripSurveyController): Handle invalid survey URL parameters. --- .../controllers/api/TripSurveyController.java | 36 ++++++--- .../middleware/models/OtpUser.java | 7 ++ .../api/TripSurveyControllerTest.java | 73 +++++++++++++++---- 3 files changed, 93 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java b/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java index 7541b352c..3fd4dd72e 100644 --- a/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java +++ b/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java @@ -2,6 +2,8 @@ import io.github.manusant.ss.SparkSwagger; import io.github.manusant.ss.rest.Endpoint; +import org.eclipse.jetty.http.HttpStatus; +import org.opentripplanner.middleware.models.MonitoredTrip; import org.opentripplanner.middleware.models.OtpUser; import org.opentripplanner.middleware.models.TripSurveyNotification; import org.opentripplanner.middleware.persistence.Persistence; @@ -12,9 +14,11 @@ import java.time.Instant; import java.util.Date; +import java.util.Optional; import static io.github.manusant.ss.descriptor.EndpointDescriptor.endpointPath; import static io.github.manusant.ss.descriptor.MethodDescriptor.path; +import static org.opentripplanner.middleware.utils.JsonUtils.logMessageAndHalt; import static org.opentripplanner.middleware.utils.NotificationUtils.TRIP_SURVEY_ID; import static org.opentripplanner.middleware.utils.NotificationUtils.TRIP_SURVEY_SUBDOMAIN; @@ -49,22 +53,34 @@ public void bind(final SparkSwagger restApi) { /** * Check that the requested survey is valid (user, trip, and notifications point to existing data). */ - private static OtpUser checkParameters(String userId, String tripId, String notificationId, Response res) { - // TODO - return Persistence.otpUsers.getById(userId); + private static OtpUser checkParameters(String userId, String tripId, String notificationId, Request request) { + OtpUser user = Persistence.otpUsers.getById(userId); + if (user == null) { + returnInvalidUrlParametersError(request); + } else { + Optional notificationOpt = user.findNotification(notificationId); + if (notificationOpt.isEmpty()) returnInvalidUrlParametersError(request); + + MonitoredTrip trip = Persistence.monitoredTrips.getById(tripId); + if (trip == null) returnInvalidUrlParametersError(request); + } + + return user; + } + + private static void returnInvalidUrlParametersError(Request request) { + logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Invalid URL parameters"); } /** * Mark notification as opened. */ private static void updateNotificationState(OtpUser user, String notificationId) { - for (TripSurveyNotification notification : user.tripSurveyNotifications) { - if (notificationId.equals(notification.id)) { - notification.timeOpened = Date.from(Instant.now()); - break; - } + Optional notificationOpt = user.findNotification(notificationId); + if (notificationOpt.isPresent()) { + notificationOpt.get().timeOpened = Date.from(Instant.now()); + Persistence.otpUsers.replace(user.id, user); } - Persistence.otpUsers.replace(user.id, user); } public static String makeTripSurveyUrl(String subdomain, String surveyId, String userId, String tripId, String notificationId) { @@ -84,7 +100,7 @@ private static boolean processCall(Request req, Response res) { String tripId = req.queryParams("trip_id"); String notificationId = req.queryParams("notification_id"); - OtpUser user = checkParameters(userId, tripId, notificationId, res); + OtpUser user = checkParameters(userId, tripId, notificationId, req); if (user != null) { String surveyUrl = makeTripSurveyUrl( diff --git a/src/main/java/org/opentripplanner/middleware/models/OtpUser.java b/src/main/java/org/opentripplanner/middleware/models/OtpUser.java index 1c9e32a02..bd2ae4b16 100644 --- a/src/main/java/org/opentripplanner/middleware/models/OtpUser.java +++ b/src/main/java/org/opentripplanner/middleware/models/OtpUser.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonSetter; +import org.apache.logging.log4j.util.Strings; import org.opentripplanner.middleware.auth.Auth0Users; import org.opentripplanner.middleware.auth.RequestingUser; import org.opentripplanner.middleware.persistence.Persistence; @@ -210,4 +211,10 @@ public Optional findLastTripSurveyNotificationSent() { if (tripSurveyNotifications == null) return Optional.empty(); return tripSurveyNotifications.stream().max(Comparator.comparingLong(n -> n.timeSent.getTime())); } + + /** Obtains a notification with the given id, if available. */ + public Optional findNotification(String id) { + if (tripSurveyNotifications == null || Strings.isBlank(id)) return Optional.empty(); + return tripSurveyNotifications.stream().filter(n -> id.equals(n.id)).findFirst(); + } } diff --git a/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java b/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java index 352f28568..28199a230 100644 --- a/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java +++ b/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java @@ -4,7 +4,11 @@ import org.eclipse.jetty.http.HttpStatus; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.middleware.models.MonitoredTrip; import org.opentripplanner.middleware.models.OtpUser; import org.opentripplanner.middleware.models.TrackedJourney; @@ -19,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -42,12 +47,6 @@ public static void setUp() throws Exception { trackedJourney = new TrackedJourney(); trackedJourney.id = UUID.randomUUID().toString(); Persistence.trackedJourneys.create(trackedJourney); - - otpUser.tripSurveyNotifications = List.of( - new TripSurveyNotification("other-notification", Date.from(Instant.now()), "other-journey"), - new TripSurveyNotification(NOTIFICATION_ID, Date.from(Instant.now()), trackedJourney.id) - ); - Persistence.otpUsers.replace(otpUser.id, otpUser); } private static MonitoredTrip createMonitoredTrip() { @@ -69,6 +68,15 @@ public static void tearDown() throws Exception { if (trackedJourney != null) trackedJourney.delete(); } + @BeforeEach + void setUpTest() { + otpUser.tripSurveyNotifications = List.of( + new TripSurveyNotification("other-notification", Date.from(Instant.now()), "other-journey"), + new TripSurveyNotification(NOTIFICATION_ID, Date.from(Instant.now()), trackedJourney.id) + ); + Persistence.otpUsers.replace(otpUser.id, otpUser); + } + @Test void canMakeTripSurveyUrl() { assertEquals( @@ -106,14 +114,53 @@ void canOpenSurveyAndUpdateNotificationStatus() { OtpUser updatedUser = Persistence.otpUsers.getById(otpUser.id); assertNotNull(updatedUser); assertEquals(otpUser.tripSurveyNotifications.size(), updatedUser.tripSurveyNotifications.size()); - updatedUser.tripSurveyNotifications.forEach(n -> { - if (NOTIFICATION_ID.equals(n.id)) { - assertNotNull(n.timeOpened); - assertTrue(n.timeOpened.toInstant().isAfter(requestInstant)); - assertTrue(n.timeOpened.toInstant().isBefore(requestCompleteInstant)); + + int updatedNotificationCount = 0; + for (TripSurveyNotification notification : updatedUser.tripSurveyNotifications) { + if (NOTIFICATION_ID.equals(notification.id)) { + assertNotNull(notification.timeOpened); + assertTrue(notification.timeOpened.toInstant().isAfter(requestInstant)); + assertTrue(notification.timeOpened.toInstant().isBefore(requestCompleteInstant)); + updatedNotificationCount++; } else { - assertNull(n.timeOpened); + assertNull(notification.timeOpened); } - }); + } + assertEquals(1, updatedNotificationCount); + } + + @ParameterizedTest + @MethodSource("createShouldRejectInvalidParamsCases") + void shouldRejectInvalidParams(String userId, String tripId, String notificationId) { + assumeTrue(IS_END_TO_END); + + var response = makeRequest( + String.format( + "api/trip-survey/open?user_id=%s&trip_id=%s¬ification_id=%s", + userId, + tripId, + notificationId + ), + "", + Map.of(), + HttpMethod.GET + ); + + assertEquals( + HttpStatus.BAD_REQUEST_400, + response.status, + "Invalid URL params should result in HTTP Status 400." + ); + } + + private static Stream createShouldRejectInvalidParamsCases() { + return Stream.of( + Arguments.of("invalid-user-id", monitoredTrip.id, NOTIFICATION_ID), + Arguments.of(null, monitoredTrip.id, NOTIFICATION_ID), + Arguments.of(otpUser.id, "invalid-trip-id", NOTIFICATION_ID), + Arguments.of(otpUser.id, null, NOTIFICATION_ID), + Arguments.of(otpUser.id, monitoredTrip.id, "invalid-notification-id"), + Arguments.of(otpUser.id, monitoredTrip.id, null) + ); } } From 26bf78aac219dd3f5b1cfcddce39514133dba74b Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 12 Dec 2024 19:04:16 -0500 Subject: [PATCH 4/7] docs(swagger): Update snapshot. --- .../latest-spark-swagger-output.yaml | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/main/resources/latest-spark-swagger-output.yaml b/src/main/resources/latest-spark-swagger-output.yaml index 60ecf59fd..41b07a291 100644 --- a/src/main/resources/latest-spark-swagger-output.yaml +++ b/src/main/resources/latest-spark-swagger-output.yaml @@ -34,6 +34,9 @@ tags: description: "Interface for reporting and retrieving application errors using Bugsnag." - name: "api/secure/connected-data" description: "Interface for listing and downloading CDP files from S3." +- name: "api/trip-survey" + description: "Interface for tracking opened trip surveys following a trip survey\ + \ notification" - name: "otp" description: "Proxy interface for OTP 2 endpoints. Refer to OTP's\ \ API documentation for OTP's supported API resources." @@ -2174,6 +2177,31 @@ paths: type: "array" items: $ref: "#/definitions/URL" + /api/trip-survey/open: + get: + tags: + - "api/trip-survey" + description: "Generates a tracking survey link for a specified user, trip, notification\ + \ ids." + parameters: + - name: "user_id" + in: "query" + description: "The id of the OtpUser that this notification applies to." + required: true + type: "string" + - name: "trip_id" + in: "query" + description: "The id of the MonitoredTrip that this notification applies to." + required: true + type: "string" + - name: "notification_id" + in: "query" + description: "The id of the notification that this notification applies to." + required: true + type: "string" + responses: + "200": + description: "successful operation" /otp/*: get: tags: @@ -3260,6 +3288,9 @@ definitions: timeSent: type: "string" format: "date" + timeOpened: + type: "string" + format: "date" journeyId: type: "string" GetUsageResult: From 9891b7b773aca87c72bdac6a3a0f1c7fd2ad1ec4 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 13 Dec 2024 17:14:32 -0500 Subject: [PATCH 5/7] fix(TripSurveyController): Set date opened on survey notification only if empty. --- .../controllers/api/TripSurveyController.java | 12 ++-- .../api/TripSurveyControllerTest.java | 61 ++++++++++--------- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java b/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java index 3fd4dd72e..4e416e97b 100644 --- a/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java +++ b/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java @@ -73,12 +73,12 @@ private static void returnInvalidUrlParametersError(Request request) { } /** - * Mark notification as opened. + * Mark notification as opened, but if an opened date is already populated, do nothing. */ - private static void updateNotificationState(OtpUser user, String notificationId) { - Optional notificationOpt = user.findNotification(notificationId); - if (notificationOpt.isPresent()) { - notificationOpt.get().timeOpened = Date.from(Instant.now()); + private static void updateNotificationStateIfNeeded(OtpUser user, String notificationId) { + TripSurveyNotification notification = user.findNotification(notificationId).orElse(null); + if (notification != null && notification.timeOpened == null) { + notification.timeOpened = Date.from(Instant.now()); Persistence.otpUsers.replace(user.id, user); } } @@ -112,7 +112,7 @@ private static boolean processCall(Request req, Response res) { ); // Update notification state - updateNotificationState(user, notificationId); + updateNotificationStateIfNeeded(user, notificationId); // Redirect res.redirect(surveyUrl); diff --git a/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java b/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java index 28199a230..31a963c59 100644 --- a/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java +++ b/src/test/java/org/opentripplanner/middleware/controllers/api/TripSurveyControllerTest.java @@ -17,6 +17,7 @@ import org.opentripplanner.middleware.testutils.ApiTestUtils; import org.opentripplanner.middleware.testutils.OtpMiddlewareTestEnvironment; import org.opentripplanner.middleware.testutils.PersistenceTestUtils; +import org.opentripplanner.middleware.utils.HttpResponseValues; import java.time.Instant; import java.util.Date; @@ -33,6 +34,7 @@ import static org.opentripplanner.middleware.testutils.ApiTestUtils.makeRequest; class TripSurveyControllerTest extends OtpMiddlewareTestEnvironment { + public static final String SURVEY_PATH_TEMPLATE = "api/trip-survey/open?user_id=%s&trip_id=%s¬ification_id=%s"; private static OtpUser otpUser; private static MonitoredTrip monitoredTrip; private static TrackedJourney trackedJourney; @@ -91,22 +93,10 @@ void canOpenSurveyAndUpdateNotificationStatus() { OtpUser existingUser = Persistence.otpUsers.getById(otpUser.id); assertNotNull(existingUser); - existingUser.tripSurveyNotifications.forEach(n -> { - assertNull(n.timeOpened); - }); + existingUser.tripSurveyNotifications.forEach(n -> assertNull(n.timeOpened)); Instant requestInstant = Instant.now(); - var response = makeRequest( - String.format( - "api/trip-survey/open?user_id=%s&trip_id=%s¬ification_id=%s", - otpUser.id, - monitoredTrip.id, - NOTIFICATION_ID - ), - "", - Map.of(), - HttpMethod.GET - ); + var response = invokeSurveyEndpoint(otpUser.id, monitoredTrip.id, NOTIFICATION_ID); Instant requestCompleteInstant = Instant.now(); assertEquals(HttpStatus.OK_200, response.status); @@ -116,17 +106,32 @@ void canOpenSurveyAndUpdateNotificationStatus() { assertEquals(otpUser.tripSurveyNotifications.size(), updatedUser.tripSurveyNotifications.size()); int updatedNotificationCount = 0; + Date notificationTimeOpened = null; for (TripSurveyNotification notification : updatedUser.tripSurveyNotifications) { if (NOTIFICATION_ID.equals(notification.id)) { - assertNotNull(notification.timeOpened); - assertTrue(notification.timeOpened.toInstant().isAfter(requestInstant)); - assertTrue(notification.timeOpened.toInstant().isBefore(requestCompleteInstant)); + notificationTimeOpened = notification.timeOpened; + assertNotNull(notificationTimeOpened); + assertTrue(notificationTimeOpened.toInstant().isAfter(requestInstant)); + assertTrue(notificationTimeOpened.toInstant().isBefore(requestCompleteInstant)); updatedNotificationCount++; } else { assertNull(notification.timeOpened); } } assertEquals(1, updatedNotificationCount); + assertNotNull(notificationTimeOpened); + + // A second request should not change the notification opened date. + var response2 = invokeSurveyEndpoint(otpUser.id, monitoredTrip.id, NOTIFICATION_ID); + assertEquals(HttpStatus.OK_200, response2.status); + + updatedUser = Persistence.otpUsers.getById(otpUser.id); + assertNotNull(updatedUser); + for (TripSurveyNotification notification : updatedUser.tripSurveyNotifications) { + if (NOTIFICATION_ID.equals(notification.id)) { + assertEquals(notificationTimeOpened, notification.timeOpened); + } + } } @ParameterizedTest @@ -134,17 +139,7 @@ void canOpenSurveyAndUpdateNotificationStatus() { void shouldRejectInvalidParams(String userId, String tripId, String notificationId) { assumeTrue(IS_END_TO_END); - var response = makeRequest( - String.format( - "api/trip-survey/open?user_id=%s&trip_id=%s¬ification_id=%s", - userId, - tripId, - notificationId - ), - "", - Map.of(), - HttpMethod.GET - ); + var response = invokeSurveyEndpoint(userId, tripId, notificationId); assertEquals( HttpStatus.BAD_REQUEST_400, @@ -163,4 +158,14 @@ private static Stream createShouldRejectInvalidParamsCases() { Arguments.of(otpUser.id, monitoredTrip.id, null) ); } + + /** Helper to invoke the survey endpoint */ + private static HttpResponseValues invokeSurveyEndpoint(String userId, String tripId, String notificationId) { + return makeRequest( + String.format(SURVEY_PATH_TEMPLATE, userId, tripId, notificationId), + "", + Map.of(), + HttpMethod.GET + ); + } } From 57460def3df01a507f5844fb74b2301d6f9e1cfe Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:10:55 -0500 Subject: [PATCH 6/7] docs(TripSurveyController): Tweak endpoint description. --- .../middleware/controllers/api/TripSurveyController.java | 2 +- src/main/resources/latest-spark-swagger-output.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java b/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java index 4e416e97b..35a897050 100644 --- a/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java +++ b/src/main/java/org/opentripplanner/middleware/controllers/api/TripSurveyController.java @@ -37,7 +37,7 @@ public TripSurveyController(String apiPrefix) { @Override public void bind(final SparkSwagger restApi) { restApi.endpoint( - endpointPath(ROOT_ROUTE).withDescription("Interface for tracking opened trip surveys following a trip survey notification"), + endpointPath(ROOT_ROUTE).withDescription("Interface for tracking opened trip surveys following a trip survey notification."), HttpUtils.NO_FILTER ) .get( diff --git a/src/main/resources/latest-spark-swagger-output.yaml b/src/main/resources/latest-spark-swagger-output.yaml index 41b07a291..a211bd6af 100644 --- a/src/main/resources/latest-spark-swagger-output.yaml +++ b/src/main/resources/latest-spark-swagger-output.yaml @@ -36,7 +36,7 @@ tags: description: "Interface for listing and downloading CDP files from S3." - name: "api/trip-survey" description: "Interface for tracking opened trip surveys following a trip survey\ - \ notification" + \ notification." - name: "otp" description: "Proxy interface for OTP 2 endpoints. Refer to OTP's\ \ API documentation for OTP's supported API resources." From d8117577c32c8e332446e5f4293ebaa3c98ea804 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:13:49 -0500 Subject: [PATCH 7/7] refactor(OtpMiddlewareMain): Reorder controllers. --- .../middleware/OtpMiddlewareMain.java | 17 +- .../latest-spark-swagger-output.yaml | 1342 ++++++++--------- 2 files changed, 679 insertions(+), 680 deletions(-) diff --git a/src/main/java/org/opentripplanner/middleware/OtpMiddlewareMain.java b/src/main/java/org/opentripplanner/middleware/OtpMiddlewareMain.java index 3b34d3bc2..b6f9093f3 100644 --- a/src/main/java/org/opentripplanner/middleware/OtpMiddlewareMain.java +++ b/src/main/java/org/opentripplanner/middleware/OtpMiddlewareMain.java @@ -121,19 +121,18 @@ private static void initializeHttpEndpoints() throws IOException { .endpoints(() -> List.of( new AdminUserController(API_PREFIX), new ApiUserController(API_PREFIX), + new CDPFilesController(API_PREFIX), new CDPUserController(API_PREFIX), + new ErrorEventsController(API_PREFIX), + new LogController(API_PREFIX), + new MonitoredComponentController(API_PREFIX), new MonitoredTripController(API_PREFIX), + new OtpRequestProcessor("/otp", OtpVersion.OTP2), + new OtpRequestProcessor("/otp2", OtpVersion.OTP2), + new OtpUserController(API_PREFIX), new TrackedTripController(API_PREFIX), new TripHistoryController(API_PREFIX), - new MonitoredComponentController(API_PREFIX), - new OtpUserController(API_PREFIX), - new LogController(API_PREFIX), - new ErrorEventsController(API_PREFIX), - new CDPFilesController(API_PREFIX), - new TripSurveyController(API_PREFIX), - new OtpRequestProcessor("/otp", OtpVersion.OTP2), - new OtpRequestProcessor("/otp2", OtpVersion.OTP2) - // Add other endpoints as needed. + new TripSurveyController(API_PREFIX) )) // Spark-swagger auto-generates a swagger document at localhost:4567/doc.yaml. // (That path is not configurable.) diff --git a/src/main/resources/latest-spark-swagger-output.yaml b/src/main/resources/latest-spark-swagger-output.yaml index a211bd6af..3e8f05d54 100644 --- a/src/main/resources/latest-spark-swagger-output.yaml +++ b/src/main/resources/latest-spark-swagger-output.yaml @@ -18,31 +18,31 @@ tags: description: "Interface for querying and managing 'AdminUser' entities." - name: "api/secure/application" description: "Interface for querying and managing 'ApiUser' entities." +- name: "api/secure/connected-data" + description: "Interface for listing and downloading CDP files from S3." - name: "api/secure/cdp" description: "Interface for querying and managing 'CDPUser' entities." -- name: "api/secure/monitoredtrip" - description: "Interface for querying and managing 'MonitoredTrip' entities." -- name: "api/secure/triprequests" - description: "Interface for retrieving trip requests." -- name: "api/secure/monitoredcomponent" - description: "Interface for querying and managing 'MonitoredComponent' entities." -- name: "api/secure/user" - description: "Interface for querying and managing 'OtpUser' entities." -- name: "api/secure/logs" - description: "Interface for retrieving API logs from AWS." - name: "api/admin/bugsnag/eventsummary" description: "Interface for reporting and retrieving application errors using Bugsnag." -- name: "api/secure/connected-data" - description: "Interface for listing and downloading CDP files from S3." -- name: "api/trip-survey" - description: "Interface for tracking opened trip surveys following a trip survey\ - \ notification." +- name: "api/secure/logs" + description: "Interface for retrieving API logs from AWS." +- name: "api/secure/monitoredcomponent" + description: "Interface for querying and managing 'MonitoredComponent' entities." +- name: "api/secure/monitoredtrip" + description: "Interface for querying and managing 'MonitoredTrip' entities." - name: "otp" description: "Proxy interface for OTP 2 endpoints. Refer to OTP's\ \ API documentation for OTP's supported API resources." - name: "otp2" description: "Proxy interface for OTP 2 endpoints. Refer to OTP's\ \ API documentation for OTP's supported API resources." +- name: "api/secure/user" + description: "Interface for querying and managing 'OtpUser' entities." +- name: "api/secure/triprequests" + description: "Interface for retrieving trip requests." +- name: "api/trip-survey" + description: "Interface for tracking opened trip surveys following a trip survey\ + \ notification." schemes: - "https" paths: @@ -744,6 +744,62 @@ paths: description: "An error occurred while performing the request. Contact an\ \ API administrator for more information." examples: {} + /api/secure/connected-data: + get: + tags: + - "api/secure/connected-data" + description: "Gets a paginated list of CDP zip files in the configured S3 bucket." + produces: + - "application/json" + parameters: + - name: "limit" + in: "query" + description: "If specified, the maximum number of items to return." + required: false + type: "string" + default: "10" + - name: "offset" + in: "query" + description: "If specified, the number of records to skip/offset." + required: false + type: "string" + default: "0" + responses: + "200": + description: "successful operation" + responseSchema: + type: "array" + items: + $ref: "#/definitions/CDPFile" + schema: + type: "array" + items: + $ref: "#/definitions/CDPFile" + /api/secure/connected-data/download: + get: + tags: + - "api/secure/connected-data" + description: "Generates a download link for a specified object within the CDP\ + \ bucket." + produces: + - "application/json" + parameters: + - name: "/download" + in: "query" + description: "The key of the object to generate a link for." + required: true + type: "string" + responses: + "200": + description: "successful operation" + responseSchema: + type: "array" + items: + $ref: "#/definitions/URL" + schema: + type: "array" + items: + $ref: "#/definitions/URL" /api/secure/cdp/fromtoken: get: tags: @@ -1034,54 +1090,83 @@ paths: description: "An error occurred while performing the request. Contact an\ \ API administrator for more information." examples: {} - /api/secure/monitoredtrip/checkitinerary: - post: + /api/admin/bugsnag/eventsummary: + get: tags: - - "api/secure/monitoredtrip" - description: "Returns the itinerary existence check results for a monitored\ - \ trip." + - "api/admin/bugsnag/eventsummary" + description: "Gets a paginated list of the latest Bugsnag event summaries." produces: - "application/json" parameters: - - in: "body" - name: "body" - description: "Body object description" - required: true - schema: - $ref: "#/definitions/MonitoredTrip" + - name: "limit" + in: "query" + description: "If specified, the maximum number of items to return." + required: false + type: "string" + default: "10" + - name: "offset" + in: "query" + description: "If specified, the number of records to skip/offset." + required: false + type: "string" + default: "0" responses: "200": - description: "Successful operation" - examples: {} + description: "successful operation" responseSchema: - $ref: "#/definitions/ItineraryExistence" + type: "array" + items: + $ref: "#/definitions/BugsnagEvent" schema: - $ref: "#/definitions/ItineraryExistence" - "400": - description: "The request was not formed properly (e.g., some required parameters\ - \ may be missing). See the details of the returned response to determine\ - \ the exact issue." - examples: {} - "401": - description: "The server was not able to authenticate the request. This\ - \ can happen if authentication headers are missing or malformed, or the\ - \ authentication server cannot be reached." - examples: {} - "403": - description: "The requesting user is not allowed to perform the request." - examples: {} - "404": - description: "The requested item was not found." - examples: {} - "500": - description: "An error occurred while performing the request. Contact an\ - \ API administrator for more information." - examples: {} - /api/secure/monitoredtrip: + type: "array" + items: + $ref: "#/definitions/BugsnagEvent" + /api/secure/logs: get: tags: - - "api/secure/monitoredtrip" - description: "Gets a paginated list of all 'MonitoredTrip' entities." + - "api/secure/logs" + description: "Gets a list of all API usage logs." + produces: + - "application/json" + parameters: + - name: "keyId" + in: "query" + description: "If specified, restricts the search to the specified AWS API\ + \ key ID." + required: false + type: "string" + - name: "startDate" + in: "query" + description: "If specified, the earliest date (format yyyy-MM-dd) for which\ + \ usage logs are retrieved." + required: false + type: "string" + default: "30 days prior to the current date" + pattern: "yyyy-MM-dd" + - name: "endDate" + in: "query" + description: "If specified, the latest date (format yyyy-MM-dd) for which\ + \ usage logs are retrieved." + required: false + type: "string" + default: "The current date" + pattern: "yyyy-MM-dd" + responses: + "200": + description: "successful operation" + responseSchema: + type: "array" + items: + $ref: "#/definitions/ApiUsageResult" + schema: + type: "array" + items: + $ref: "#/definitions/ApiUsageResult" + /api/secure/monitoredcomponent: + get: + tags: + - "api/secure/monitoredcomponent" + description: "Gets a paginated list of all 'MonitoredComponent' entities." produces: - "application/json" parameters: @@ -1111,8 +1196,8 @@ paths: $ref: "#/definitions/ResponseList" post: tags: - - "api/secure/monitoredtrip" - description: "Creates a 'MonitoredTrip' entity." + - "api/secure/monitoredcomponent" + description: "Creates a 'MonitoredComponent' entity." consumes: - "application/json" produces: @@ -1123,15 +1208,15 @@ paths: description: "Body object description" required: true schema: - $ref: "#/definitions/MonitoredTrip" + $ref: "#/definitions/MonitoredComponent" responses: "200": description: "Successful operation" examples: {} responseSchema: - $ref: "#/definitions/MonitoredTrip" + $ref: "#/definitions/MonitoredComponent" schema: - $ref: "#/definitions/MonitoredTrip" + $ref: "#/definitions/MonitoredComponent" "400": description: "The request was not formed properly (e.g., some required parameters\ \ may be missing). See the details of the returned response to determine\ @@ -1152,12 +1237,12 @@ paths: description: "An error occurred while performing the request. Contact an\ \ API administrator for more information." examples: {} - /api/secure/monitoredtrip/{id}: + /api/secure/monitoredcomponent/{id}: get: tags: - - "api/secure/monitoredtrip" - description: "Returns the 'MonitoredTrip' entity with the specified id, or 404\ - \ if not found." + - "api/secure/monitoredcomponent" + description: "Returns the 'MonitoredComponent' entity with the specified id,\ + \ or 404 if not found." produces: - "application/json" parameters: @@ -1171,9 +1256,9 @@ paths: description: "Successful operation" examples: {} responseSchema: - $ref: "#/definitions/MonitoredTrip" + $ref: "#/definitions/MonitoredComponent" schema: - $ref: "#/definitions/MonitoredTrip" + $ref: "#/definitions/MonitoredComponent" "400": description: "The request was not formed properly (e.g., some required parameters\ \ may be missing). See the details of the returned response to determine\ @@ -1196,8 +1281,8 @@ paths: examples: {} put: tags: - - "api/secure/monitoredtrip" - description: "Updates and returns the 'MonitoredTrip' entity with the specified\ + - "api/secure/monitoredcomponent" + description: "Updates and returns the 'MonitoredComponent' entity with the specified\ \ id, or 404 if not found." consumes: - "application/json" @@ -1214,15 +1299,15 @@ paths: description: "Body object description" required: true schema: - $ref: "#/definitions/MonitoredTrip" + $ref: "#/definitions/MonitoredComponent" responses: "200": description: "Successful operation" examples: {} responseSchema: - $ref: "#/definitions/MonitoredTrip" + $ref: "#/definitions/MonitoredComponent" schema: - $ref: "#/definitions/MonitoredTrip" + $ref: "#/definitions/MonitoredComponent" "400": description: "The request was not formed properly (e.g., some required parameters\ \ may be missing). See the details of the returned response to determine\ @@ -1245,9 +1330,9 @@ paths: examples: {} delete: tags: - - "api/secure/monitoredtrip" - description: "Deletes the 'MonitoredTrip' entity with the specified id if it\ - \ exists." + - "api/secure/monitoredcomponent" + description: "Deletes the 'MonitoredComponent' entity with the specified id\ + \ if it exists." produces: - "application/json" parameters: @@ -1261,9 +1346,9 @@ paths: description: "Successful operation" examples: {} responseSchema: - $ref: "#/definitions/MonitoredTrip" + $ref: "#/definitions/MonitoredComponent" schema: - $ref: "#/definitions/MonitoredTrip" + $ref: "#/definitions/MonitoredComponent" "400": description: "The request was not formed properly (e.g., some required parameters\ \ may be missing). See the details of the returned response to determine\ @@ -1284,11 +1369,12 @@ paths: description: "An error occurred while performing the request. Contact an\ \ API administrator for more information." examples: {} - /api/secure/monitoredtrip/starttracking: + /api/secure/monitoredtrip/checkitinerary: post: tags: - "api/secure/monitoredtrip" - description: "Initiates the tracking of a monitored trip." + description: "Returns the itinerary existence check results for a monitored\ + \ trip." produces: - "application/json" parameters: @@ -1297,151 +1383,40 @@ paths: description: "Body object description" required: true schema: - $ref: "#/definitions/StartTrackingPayload" + $ref: "#/definitions/MonitoredTrip" responses: "200": - description: "successful operation" + description: "Successful operation" + examples: {} responseSchema: - $ref: "#/definitions/TrackingResponse" + $ref: "#/definitions/ItineraryExistence" schema: - $ref: "#/definitions/TrackingResponse" - /api/secure/monitoredtrip/updatetracking: - post: - tags: - - "api/secure/monitoredtrip" - description: "Provides tracking updates on a monitored trip." - produces: - - "application/json" - parameters: - - in: "body" - name: "body" - description: "Body object description" - required: true - schema: - $ref: "#/definitions/UpdatedTrackingPayload" - responses: - "200": - description: "successful operation" - responseSchema: - $ref: "#/definitions/TrackingResponse" - schema: - $ref: "#/definitions/TrackingResponse" - /api/secure/monitoredtrip/track: - post: - tags: - - "api/secure/monitoredtrip" - description: "Starts or updates tracking on a monitored trip." - produces: - - "application/json" - parameters: - - in: "body" - name: "body" - description: "Body object description" - required: true - schema: - $ref: "#/definitions/TrackPayload" - responses: - "200": - description: "successful operation" - responseSchema: - $ref: "#/definitions/TrackingResponse" - schema: - $ref: "#/definitions/TrackingResponse" - /api/secure/monitoredtrip/endtracking: - post: - tags: - - "api/secure/monitoredtrip" - description: "Terminates the tracking of a monitored trip by the user." - produces: - - "application/json" - parameters: - - in: "body" - name: "body" - description: "Body object description" - required: true - schema: - $ref: "#/definitions/EndTrackingPayload" - responses: - "200": - description: "successful operation" - responseSchema: - $ref: "#/definitions/EndTrackingResponse" - schema: - $ref: "#/definitions/EndTrackingResponse" - /api/secure/monitoredtrip/forciblyendtracking: - post: - tags: - - "api/secure/monitoredtrip" - description: "Forcibly terminates tracking of a monitored trip by trip ID." - produces: - - "application/json" - parameters: - - in: "body" - name: "body" - description: "Body object description" - required: true - schema: - $ref: "#/definitions/ForceEndTrackingPayload" - responses: - "200": - description: "successful operation" - responseSchema: - $ref: "#/definitions/EndTrackingResponse" - schema: - $ref: "#/definitions/EndTrackingResponse" - /api/secure/triprequests: - get: - tags: - - "api/secure/triprequests" - description: "Gets a paginated list of the most recent trip requests for a user." - produces: - - "application/json" - parameters: - - name: "userId" - in: "query" - description: "The OTP user for which to retrieve trip requests." - required: true - type: "string" - - name: "limit" - in: "query" - description: "If specified, the maximum number of items to return." - required: false - type: "string" - default: "10" - - name: "offset" - in: "query" - description: "If specified, the number of records to skip/offset." - required: false - type: "string" - default: "0" - - name: "fromDate" - in: "query" - description: "If specified, the earliest date (format yyyy-MM-dd) for which\ - \ trip requests are retrieved." - required: false - type: "string" - default: "The current date" - pattern: "yyyy-MM-dd" - - name: "toDate" - in: "query" - description: "If specified, the latest date (format yyyy-MM-dd) for which\ - \ trip requests are retrieved." - required: false - type: "string" - default: "The current date" - pattern: "yyyy-MM-dd" - responses: - "200": - description: "successful operation" - responseSchema: - $ref: "#/definitions/TripRequest" - schema: - $ref: "#/definitions/TripRequest" - /api/secure/monitoredcomponent: + $ref: "#/definitions/ItineraryExistence" + "400": + description: "The request was not formed properly (e.g., some required parameters\ + \ may be missing). See the details of the returned response to determine\ + \ the exact issue." + examples: {} + "401": + description: "The server was not able to authenticate the request. This\ + \ can happen if authentication headers are missing or malformed, or the\ + \ authentication server cannot be reached." + examples: {} + "403": + description: "The requesting user is not allowed to perform the request." + examples: {} + "404": + description: "The requested item was not found." + examples: {} + "500": + description: "An error occurred while performing the request. Contact an\ + \ API administrator for more information." + examples: {} + /api/secure/monitoredtrip: get: tags: - - "api/secure/monitoredcomponent" - description: "Gets a paginated list of all 'MonitoredComponent' entities." + - "api/secure/monitoredtrip" + description: "Gets a paginated list of all 'MonitoredTrip' entities." produces: - "application/json" parameters: @@ -1471,8 +1446,8 @@ paths: $ref: "#/definitions/ResponseList" post: tags: - - "api/secure/monitoredcomponent" - description: "Creates a 'MonitoredComponent' entity." + - "api/secure/monitoredtrip" + description: "Creates a 'MonitoredTrip' entity." consumes: - "application/json" produces: @@ -1483,15 +1458,15 @@ paths: description: "Body object description" required: true schema: - $ref: "#/definitions/MonitoredComponent" + $ref: "#/definitions/MonitoredTrip" responses: "200": description: "Successful operation" examples: {} responseSchema: - $ref: "#/definitions/MonitoredComponent" + $ref: "#/definitions/MonitoredTrip" schema: - $ref: "#/definitions/MonitoredComponent" + $ref: "#/definitions/MonitoredTrip" "400": description: "The request was not formed properly (e.g., some required parameters\ \ may be missing). See the details of the returned response to determine\ @@ -1512,12 +1487,12 @@ paths: description: "An error occurred while performing the request. Contact an\ \ API administrator for more information." examples: {} - /api/secure/monitoredcomponent/{id}: + /api/secure/monitoredtrip/{id}: get: tags: - - "api/secure/monitoredcomponent" - description: "Returns the 'MonitoredComponent' entity with the specified id,\ - \ or 404 if not found." + - "api/secure/monitoredtrip" + description: "Returns the 'MonitoredTrip' entity with the specified id, or 404\ + \ if not found." produces: - "application/json" parameters: @@ -1531,9 +1506,9 @@ paths: description: "Successful operation" examples: {} responseSchema: - $ref: "#/definitions/MonitoredComponent" + $ref: "#/definitions/MonitoredTrip" schema: - $ref: "#/definitions/MonitoredComponent" + $ref: "#/definitions/MonitoredTrip" "400": description: "The request was not formed properly (e.g., some required parameters\ \ may be missing). See the details of the returned response to determine\ @@ -1556,8 +1531,8 @@ paths: examples: {} put: tags: - - "api/secure/monitoredcomponent" - description: "Updates and returns the 'MonitoredComponent' entity with the specified\ + - "api/secure/monitoredtrip" + description: "Updates and returns the 'MonitoredTrip' entity with the specified\ \ id, or 404 if not found." consumes: - "application/json" @@ -1574,15 +1549,15 @@ paths: description: "Body object description" required: true schema: - $ref: "#/definitions/MonitoredComponent" + $ref: "#/definitions/MonitoredTrip" responses: "200": description: "Successful operation" examples: {} responseSchema: - $ref: "#/definitions/MonitoredComponent" + $ref: "#/definitions/MonitoredTrip" schema: - $ref: "#/definitions/MonitoredComponent" + $ref: "#/definitions/MonitoredTrip" "400": description: "The request was not formed properly (e.g., some required parameters\ \ may be missing). See the details of the returned response to determine\ @@ -1605,9 +1580,9 @@ paths: examples: {} delete: tags: - - "api/secure/monitoredcomponent" - description: "Deletes the 'MonitoredComponent' entity with the specified id\ - \ if it exists." + - "api/secure/monitoredtrip" + description: "Deletes the 'MonitoredTrip' entity with the specified id if it\ + \ exists." produces: - "application/json" parameters: @@ -1621,9 +1596,9 @@ paths: description: "Successful operation" examples: {} responseSchema: - $ref: "#/definitions/MonitoredComponent" + $ref: "#/definitions/MonitoredTrip" schema: - $ref: "#/definitions/MonitoredComponent" + $ref: "#/definitions/MonitoredTrip" "400": description: "The request was not formed properly (e.g., some required parameters\ \ may be missing). See the details of the returned response to determine\ @@ -1644,50 +1619,122 @@ paths: description: "An error occurred while performing the request. Contact an\ \ API administrator for more information." examples: {} - /api/secure/user/acceptdependent: + /otp/*: get: tags: - - "api/secure/user" - description: "Accept a dependent request." - parameters: [] + - "otp" + description: "Forwards any GET request to OTP 2. Refer to OTP's\ + \ API documentation for OTP's supported API resources." + produces: + - "application/json" + - "application/xml" + parameters: + - name: "userId" + in: "query" + description: "If a third-party application is making a trip plan request on\ + \ behalf of an end user (OtpUser), the user id must be specified." + required: false + type: "string" responses: "200": - description: "Successful operation" - examples: {} - responseSchema: - $ref: "#/definitions/OtpUser" - schema: - $ref: "#/definitions/OtpUser" - "400": - description: "The request was not formed properly (e.g., some required parameters\ - \ may be missing). See the details of the returned response to determine\ - \ the exact issue." - examples: {} - "401": - description: "The server was not able to authenticate the request. This\ - \ can happen if authentication headers are missing or malformed, or the\ - \ authentication server cannot be reached." - examples: {} - "403": - description: "The requesting user is not allowed to perform the request." - examples: {} - "404": - description: "The requested item was not found." - examples: {} - "500": - description: "An error occurred while performing the request. Contact an\ - \ API administrator for more information." - examples: {} - /api/secure/user/getdependentmobilityprofile: - get: + description: "successful operation" + post: tags: - - "api/secure/user" - description: "Retrieve the mobility profile for each valid dependent user id\ - \ provided." - parameters: [] + - "otp" + description: "Forwards any POST request to OTP 2. Refer to OTP's\ + \ API documentation for OTP's supported API resources." + produces: + - "application/json" + parameters: + - name: "userId" + in: "query" + description: "If a third-party application is making a trip plan request on\ + \ behalf of an end user (OtpUser), the user id must be specified." + required: false + type: "string" responses: "200": - description: "Successful operation" + description: "successful operation" + /otp2/*: + get: + tags: + - "otp2" + description: "Forwards any GET request to OTP 2. Refer to OTP's\ + \ API documentation for OTP's supported API resources." + produces: + - "application/json" + - "application/xml" + parameters: + - name: "userId" + in: "query" + description: "If a third-party application is making a trip plan request on\ + \ behalf of an end user (OtpUser), the user id must be specified." + required: false + type: "string" + responses: + "200": + description: "successful operation" + post: + tags: + - "otp2" + description: "Forwards any POST request to OTP 2. Refer to OTP's\ + \ API documentation for OTP's supported API resources." + produces: + - "application/json" + parameters: + - name: "userId" + in: "query" + description: "If a third-party application is making a trip plan request on\ + \ behalf of an end user (OtpUser), the user id must be specified." + required: false + type: "string" + responses: + "200": + description: "successful operation" + /api/secure/user/acceptdependent: + get: + tags: + - "api/secure/user" + description: "Accept a dependent request." + parameters: [] + responses: + "200": + description: "Successful operation" + examples: {} + responseSchema: + $ref: "#/definitions/OtpUser" + schema: + $ref: "#/definitions/OtpUser" + "400": + description: "The request was not formed properly (e.g., some required parameters\ + \ may be missing). See the details of the returned response to determine\ + \ the exact issue." + examples: {} + "401": + description: "The server was not able to authenticate the request. This\ + \ can happen if authentication headers are missing or malformed, or the\ + \ authentication server cannot be reached." + examples: {} + "403": + description: "The requesting user is not allowed to perform the request." + examples: {} + "404": + description: "The requested item was not found." + examples: {} + "500": + description: "An error occurred while performing the request. Contact an\ + \ API administrator for more information." + examples: {} + /api/secure/user/getdependentmobilityprofile: + get: + tags: + - "api/secure/user" + description: "Retrieve the mobility profile for each valid dependent user id\ + \ provided." + parameters: [] + responses: + "200": + description: "Successful operation" examples: {} responseSchema: $ref: "#/definitions/MobilityProfileLite" @@ -2049,227 +2096,180 @@ paths: description: "An error occurred while performing the request. Contact an\ \ API administrator for more information." examples: {} - /api/secure/logs: - get: + /api/secure/monitoredtrip/starttracking: + post: tags: - - "api/secure/logs" - description: "Gets a list of all API usage logs." + - "api/secure/monitoredtrip" + description: "Initiates the tracking of a monitored trip." produces: - "application/json" parameters: - - name: "keyId" - in: "query" - description: "If specified, restricts the search to the specified AWS API\ - \ key ID." - required: false - type: "string" - - name: "startDate" - in: "query" - description: "If specified, the earliest date (format yyyy-MM-dd) for which\ - \ usage logs are retrieved." - required: false - type: "string" - default: "30 days prior to the current date" - pattern: "yyyy-MM-dd" - - name: "endDate" - in: "query" - description: "If specified, the latest date (format yyyy-MM-dd) for which\ - \ usage logs are retrieved." - required: false - type: "string" - default: "The current date" - pattern: "yyyy-MM-dd" + - in: "body" + name: "body" + description: "Body object description" + required: true + schema: + $ref: "#/definitions/StartTrackingPayload" responses: "200": description: "successful operation" responseSchema: - type: "array" - items: - $ref: "#/definitions/ApiUsageResult" + $ref: "#/definitions/TrackingResponse" schema: - type: "array" - items: - $ref: "#/definitions/ApiUsageResult" - /api/admin/bugsnag/eventsummary: - get: + $ref: "#/definitions/TrackingResponse" + /api/secure/monitoredtrip/updatetracking: + post: tags: - - "api/admin/bugsnag/eventsummary" - description: "Gets a paginated list of the latest Bugsnag event summaries." + - "api/secure/monitoredtrip" + description: "Provides tracking updates on a monitored trip." produces: - "application/json" parameters: - - name: "limit" - in: "query" - description: "If specified, the maximum number of items to return." - required: false - type: "string" - default: "10" - - name: "offset" - in: "query" - description: "If specified, the number of records to skip/offset." - required: false - type: "string" - default: "0" + - in: "body" + name: "body" + description: "Body object description" + required: true + schema: + $ref: "#/definitions/UpdatedTrackingPayload" responses: "200": description: "successful operation" responseSchema: - type: "array" - items: - $ref: "#/definitions/BugsnagEvent" + $ref: "#/definitions/TrackingResponse" schema: - type: "array" - items: - $ref: "#/definitions/BugsnagEvent" - /api/secure/connected-data: - get: + $ref: "#/definitions/TrackingResponse" + /api/secure/monitoredtrip/track: + post: tags: - - "api/secure/connected-data" - description: "Gets a paginated list of CDP zip files in the configured S3 bucket." + - "api/secure/monitoredtrip" + description: "Starts or updates tracking on a monitored trip." produces: - "application/json" parameters: - - name: "limit" - in: "query" - description: "If specified, the maximum number of items to return." - required: false - type: "string" - default: "10" - - name: "offset" - in: "query" - description: "If specified, the number of records to skip/offset." - required: false - type: "string" - default: "0" + - in: "body" + name: "body" + description: "Body object description" + required: true + schema: + $ref: "#/definitions/TrackPayload" responses: "200": description: "successful operation" responseSchema: - type: "array" - items: - $ref: "#/definitions/CDPFile" + $ref: "#/definitions/TrackingResponse" schema: - type: "array" - items: - $ref: "#/definitions/CDPFile" - /api/secure/connected-data/download: - get: + $ref: "#/definitions/TrackingResponse" + /api/secure/monitoredtrip/endtracking: + post: tags: - - "api/secure/connected-data" - description: "Generates a download link for a specified object within the CDP\ - \ bucket." + - "api/secure/monitoredtrip" + description: "Terminates the tracking of a monitored trip by the user." produces: - "application/json" parameters: - - name: "/download" - in: "query" - description: "The key of the object to generate a link for." + - in: "body" + name: "body" + description: "Body object description" required: true - type: "string" + schema: + $ref: "#/definitions/EndTrackingPayload" responses: "200": description: "successful operation" responseSchema: - type: "array" - items: - $ref: "#/definitions/URL" + $ref: "#/definitions/EndTrackingResponse" schema: - type: "array" - items: - $ref: "#/definitions/URL" - /api/trip-survey/open: - get: + $ref: "#/definitions/EndTrackingResponse" + /api/secure/monitoredtrip/forciblyendtracking: + post: tags: - - "api/trip-survey" - description: "Generates a tracking survey link for a specified user, trip, notification\ - \ ids." + - "api/secure/monitoredtrip" + description: "Forcibly terminates tracking of a monitored trip by trip ID." + produces: + - "application/json" parameters: - - name: "user_id" - in: "query" - description: "The id of the OtpUser that this notification applies to." - required: true - type: "string" - - name: "trip_id" - in: "query" - description: "The id of the MonitoredTrip that this notification applies to." - required: true - type: "string" - - name: "notification_id" - in: "query" - description: "The id of the notification that this notification applies to." + - in: "body" + name: "body" + description: "Body object description" required: true - type: "string" + schema: + $ref: "#/definitions/ForceEndTrackingPayload" responses: "200": description: "successful operation" - /otp/*: + responseSchema: + $ref: "#/definitions/EndTrackingResponse" + schema: + $ref: "#/definitions/EndTrackingResponse" + /api/secure/triprequests: get: tags: - - "otp" - description: "Forwards any GET request to OTP 2. Refer to OTP's\ - \ API documentation for OTP's supported API resources." + - "api/secure/triprequests" + description: "Gets a paginated list of the most recent trip requests for a user." produces: - "application/json" - - "application/xml" parameters: - name: "userId" in: "query" - description: "If a third-party application is making a trip plan request on\ - \ behalf of an end user (OtpUser), the user id must be specified." + description: "The OTP user for which to retrieve trip requests." + required: true + type: "string" + - name: "limit" + in: "query" + description: "If specified, the maximum number of items to return." required: false type: "string" - responses: - "200": - description: "successful operation" - post: - tags: - - "otp" - description: "Forwards any POST request to OTP 2. Refer to OTP's\ - \ API documentation for OTP's supported API resources." - produces: - - "application/json" - parameters: - - name: "userId" + default: "10" + - name: "offset" in: "query" - description: "If a third-party application is making a trip plan request on\ - \ behalf of an end user (OtpUser), the user id must be specified." + description: "If specified, the number of records to skip/offset." required: false type: "string" - responses: - "200": - description: "successful operation" - /otp2/*: - get: - tags: - - "otp2" - description: "Forwards any GET request to OTP 2. Refer to OTP's\ - \ API documentation for OTP's supported API resources." - produces: - - "application/json" - - "application/xml" - parameters: - - name: "userId" + default: "0" + - name: "fromDate" in: "query" - description: "If a third-party application is making a trip plan request on\ - \ behalf of an end user (OtpUser), the user id must be specified." + description: "If specified, the earliest date (format yyyy-MM-dd) for which\ + \ trip requests are retrieved." + required: false + type: "string" + default: "The current date" + pattern: "yyyy-MM-dd" + - name: "toDate" + in: "query" + description: "If specified, the latest date (format yyyy-MM-dd) for which\ + \ trip requests are retrieved." required: false type: "string" + default: "The current date" + pattern: "yyyy-MM-dd" responses: "200": description: "successful operation" - post: + responseSchema: + $ref: "#/definitions/TripRequest" + schema: + $ref: "#/definitions/TripRequest" + /api/trip-survey/open: + get: tags: - - "otp2" - description: "Forwards any POST request to OTP 2. Refer to OTP's\ - \ API documentation for OTP's supported API resources." - produces: - - "application/json" + - "api/trip-survey" + description: "Generates a tracking survey link for a specified user, trip, notification\ + \ ids." parameters: - - name: "userId" + - name: "user_id" in: "query" - description: "If a third-party application is making a trip plan request on\ - \ behalf of an end user (OtpUser), the user id must be specified." - required: false + description: "The id of the OtpUser that this notification applies to." + required: true + type: "string" + - name: "trip_id" + in: "query" + description: "The id of the MonitoredTrip that this notification applies to." + required: true + type: "string" + - name: "notification_id" + in: "query" + description: "The id of the notification that this notification applies to." + required: true type: "string" responses: "200": @@ -2359,6 +2359,47 @@ definitions: type: "boolean" name: type: "string" + CDPFile: + type: "object" + properties: + key: + type: "string" + name: + type: "string" + size: + type: "integer" + format: "int64" + URL: + type: "object" + properties: + protocol: + type: "string" + host: + type: "string" + port: + type: "integer" + format: "int32" + file: + type: "string" + query: + type: "string" + authority: + type: "string" + path: + type: "string" + userInfo: + type: "string" + ref: + type: "string" + hostAddress: + $ref: "#/definitions/InetAddress" + handler: + $ref: "#/definitions/URLStreamHandler" + hashCode: + type: "integer" + format: "int32" + tempState: + $ref: "#/definitions/UrlDeserializedState" CDPUser: type: "object" properties: @@ -2366,6 +2407,69 @@ definitions: type: "string" S3DownloadTimes: $ref: "#/definitions/Map" + App: + type: "object" + properties: + releaseStage: + type: "string" + BugsnagEvent: + type: "object" + properties: + eventDataId: + type: "string" + projectId: + type: "string" + errorId: + type: "string" + receivedAt: + type: "string" + format: "date" + exceptions: + type: "array" + items: + $ref: "#/definitions/EventException" + severity: + type: "string" + context: + type: "string" + unhandled: + type: "boolean" + app: + $ref: "#/definitions/App" + EventException: + type: "object" + properties: + errorClass: + type: "string" + message: + type: "string" + GetUsageResult: + type: "object" + properties: + usagePlanId: + type: "string" + startDate: + type: "string" + endDate: + type: "string" + position: + type: "string" + items: + $ref: "#/definitions/Map" + ApiUsageResult: + type: "object" + properties: + result: + $ref: "#/definitions/GetUsageResult" + apiUsers: + $ref: "#/definitions/Map" + MonitoredComponent: + type: "object" + properties: + bugsnagProjectId: + type: "string" + name: + type: "string" TripStop: type: "object" properties: @@ -3019,200 +3123,33 @@ definitions: type: "string" address: type: "string" - StartTrackingPayload: + VerificationResult: type: "object" properties: - location: - $ref: "#/definitions/TrackingLocation" - tripId: + sid: type: "string" - TrackingLocation: + status: + type: "string" + valid: + type: "boolean" + UserLocation: type: "object" properties: - bearing: - type: "integer" - format: "int32" - lat: - type: "number" - format: "double" - lon: - type: "number" - format: "double" - speed: - type: "integer" - format: "int32" - timestamp: + address: type: "string" - format: "date" - tripStatus: + icon: type: "string" - enum: - - "ON_SCHEDULE" - - "BEHIND_SCHEDULE" - - "AHEAD_OF_SCHEDULE" - - "ENDED" - - "DEVIATED" - - "COMPLETED" - locationAccuracy: + lat: type: "number" format: "double" - deviationMeters: + lon: type: "number" format: "double" - TrackingResponse: - type: "object" - properties: - frequencySeconds: - type: "integer" - format: "int32" - instruction: - type: "string" - journeyId: - type: "string" - tripStatus: + name: type: "string" - message: + type: type: "string" - UpdatedTrackingPayload: - type: "object" - properties: - journeyId: - type: "string" - locations: - type: "array" - items: - $ref: "#/definitions/TrackingLocation" - TrackPayload: - type: "object" - properties: - locations: - type: "array" - items: - $ref: "#/definitions/TrackingLocation" - tripId: - type: "string" - EndTrackingPayload: - type: "object" - properties: - journeyId: - type: "string" - EndTrackingResponse: - type: "object" - properties: - instruction: - type: "string" - tripStatus: - type: "string" - message: - type: "string" - ForceEndTrackingPayload: - type: "object" - properties: - tripId: - type: "string" - TripRequest: - type: "object" - properties: - userId: - type: "string" - batchId: - type: "string" - fromPlace: - type: "string" - toPlace: - type: "string" - otp2QueryParams: - $ref: "#/definitions/QueryVariables" - QueryVariables: - type: "object" - properties: - arriveBy: - type: "boolean" - banned: - $ref: "#/definitions/RoutesAndTrips" - bikeReluctance: - type: "number" - format: "float" - carReluctance: - type: "number" - format: "float" - date: - type: "string" - fromPlace: - type: "string" - mobilityProfile: - type: "string" - modes: - type: "array" - items: - $ref: "#/definitions/TransportMode" - numItineraries: - type: "integer" - format: "int32" - preferred: - $ref: "#/definitions/RoutesAndTrips" - time: - type: "string" - toPlace: - type: "string" - unpreferred: - $ref: "#/definitions/RoutesAndTrips" - walkReluctance: - type: "number" - format: "float" - walkSpeed: - type: "number" - format: "float" - wheelchair: - type: "boolean" - RoutesAndTrips: - type: "object" - properties: - routes: - type: "string" - trips: - type: "string" - TransportMode: - type: "object" - properties: - mode: - type: "string" - qualifier: - type: "string" - MonitoredComponent: - type: "object" - properties: - bugsnagProjectId: - type: "string" - name: - type: "string" - VerificationResult: - type: "object" - properties: - sid: - type: "string" - status: - type: "string" - valid: - type: "boolean" - UserLocation: - type: "object" - properties: - address: - type: "string" - icon: - type: "string" - lat: - type: "number" - format: "double" - lon: - type: "number" - format: "double" - name: - type: "string" - type: - type: "string" - OtpUser: + OtpUser: type: "object" properties: accessibilityRoutingByDefault: @@ -3293,103 +3230,166 @@ definitions: format: "date" journeyId: type: "string" - GetUsageResult: + StartTrackingPayload: type: "object" properties: - usagePlanId: - type: "string" - startDate: - type: "string" - endDate: - type: "string" - position: + location: + $ref: "#/definitions/TrackingLocation" + tripId: type: "string" - items: - $ref: "#/definitions/Map" - ApiUsageResult: - type: "object" - properties: - result: - $ref: "#/definitions/GetUsageResult" - apiUsers: - $ref: "#/definitions/Map" - App: + TrackingLocation: type: "object" properties: - releaseStage: + bearing: + type: "integer" + format: "int32" + lat: + type: "number" + format: "double" + lon: + type: "number" + format: "double" + speed: + type: "integer" + format: "int32" + timestamp: type: "string" - BugsnagEvent: + format: "date" + tripStatus: + type: "string" + enum: + - "ON_SCHEDULE" + - "BEHIND_SCHEDULE" + - "AHEAD_OF_SCHEDULE" + - "ENDED" + - "DEVIATED" + - "COMPLETED" + locationAccuracy: + type: "number" + format: "double" + deviationMeters: + type: "number" + format: "double" + TrackingResponse: type: "object" properties: - eventDataId: + frequencySeconds: + type: "integer" + format: "int32" + instruction: type: "string" - projectId: + journeyId: type: "string" - errorId: + tripStatus: type: "string" - receivedAt: + message: type: "string" - format: "date" - exceptions: + UpdatedTrackingPayload: + type: "object" + properties: + journeyId: + type: "string" + locations: type: "array" items: - $ref: "#/definitions/EventException" - severity: + $ref: "#/definitions/TrackingLocation" + TrackPayload: + type: "object" + properties: + locations: + type: "array" + items: + $ref: "#/definitions/TrackingLocation" + tripId: type: "string" - context: + EndTrackingPayload: + type: "object" + properties: + journeyId: type: "string" - unhandled: - type: "boolean" - app: - $ref: "#/definitions/App" - EventException: + EndTrackingResponse: type: "object" properties: - errorClass: + instruction: + type: "string" + tripStatus: type: "string" message: type: "string" - CDPFile: + ForceEndTrackingPayload: type: "object" properties: - key: + tripId: type: "string" - name: + TripRequest: + type: "object" + properties: + userId: type: "string" - size: - type: "integer" - format: "int64" - URL: + batchId: + type: "string" + fromPlace: + type: "string" + toPlace: + type: "string" + otp2QueryParams: + $ref: "#/definitions/QueryVariables" + QueryVariables: type: "object" properties: - protocol: + arriveBy: + type: "boolean" + banned: + $ref: "#/definitions/RoutesAndTrips" + bikeReluctance: + type: "number" + format: "float" + carReluctance: + type: "number" + format: "float" + date: type: "string" - host: + fromPlace: type: "string" - port: + mobilityProfile: + type: "string" + modes: + type: "array" + items: + $ref: "#/definitions/TransportMode" + numItineraries: type: "integer" format: "int32" - file: + preferred: + $ref: "#/definitions/RoutesAndTrips" + time: type: "string" - query: + toPlace: type: "string" - authority: + unpreferred: + $ref: "#/definitions/RoutesAndTrips" + walkReluctance: + type: "number" + format: "float" + walkSpeed: + type: "number" + format: "float" + wheelchair: + type: "boolean" + RoutesAndTrips: + type: "object" + properties: + routes: type: "string" - path: + trips: type: "string" - userInfo: + TransportMode: + type: "object" + properties: + mode: type: "string" - ref: + qualifier: type: "string" - hostAddress: - $ref: "#/definitions/InetAddress" - handler: - $ref: "#/definitions/URLStreamHandler" - hashCode: - type: "integer" - format: "int32" - tempState: - $ref: "#/definitions/UrlDeserializedState" externalDocs: description: "" url: ""