From c0e86127c13b7449e57cb87a5b130f3c8454384c Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Wed, 6 Nov 2024 15:31:05 +0000 Subject: [PATCH 1/8] refactor(Initial work to provide a dependent's mobility profile): --- .../controllers/api/OtpUserController.java | 19 ++++++ .../tripmonitor/TrustedCompanion.java | 46 +++++++++++++-- .../api/OtpUserControllerTest.java | 58 +++++++++++++++---- 3 files changed, 107 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java b/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java index 096518d9e..c1445e513 100644 --- a/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java +++ b/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java @@ -7,6 +7,7 @@ import org.eclipse.jetty.http.HttpStatus; import org.opentripplanner.middleware.auth.Auth0Connection; import org.opentripplanner.middleware.auth.RequestingUser; +import org.opentripplanner.middleware.models.MobilityProfile; import org.opentripplanner.middleware.models.OtpUser; import org.opentripplanner.middleware.persistence.Persistence; import org.opentripplanner.middleware.tripmonitor.TrustedCompanion; @@ -25,6 +26,8 @@ import static io.github.manusant.ss.descriptor.MethodDescriptor.path; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.ACCEPT_KEY; +import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.EMAIL_PARAM; +import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.GET_DEPENDENT_MOBILITY_PROFILE_PATH; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.USER_LOCALE; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.ensureRelatedUserIntegrity; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.manageAcceptDependentEmail; @@ -100,6 +103,14 @@ protected void buildEndpoint(ApiEndpoint baseEndpoint) { .withResponseType(OtpUser.class), TrustedCompanion::acceptDependent ) + .get(path(ROOT_ROUTE + String.format(GET_DEPENDENT_MOBILITY_PROFILE_PATH, ID_PARAM)) + .withDescription("Retrieve a dependent's mobility profile.") + .withResponses(SwaggerUtils.createStandardResponses(MobilityProfile.class)) + .withPathParam().withName(ID_PARAM).withRequired(true).withDescription("The id of the related user.").and() + .withPathParam().withName(EMAIL_PARAM).withRequired(true).withDescription("The dependent's email address.").and() + .withResponseType(MobilityProfile.class), + this::getDependentMobilityProfile, JsonUtils::toJson + ) .get(path(ROOT_ROUTE + String.format(VERIFY_ROUTE_TEMPLATE, ID_PARAM, VERIFY_PATH, PHONE_PARAM)) .withDescription("Request an SMS verification to be sent to an OtpUser's phone number.") .withPathParam().withName(ID_PARAM).withRequired(true).withDescription("The id of the OtpUser.").and() @@ -128,6 +139,14 @@ protected OtpUser getUserProfile(RequestingUser profile) { return otpUser; } + /** + * Extract the related user from the request and return a dependent's mobility profile if the right conditions + * are met. + */ + private MobilityProfile getDependentMobilityProfile(Request request, Response response) { + return TrustedCompanion.getDependentMobilityProfile(request, response, getEntityForId(request, response)); + } + /** * HTTP endpoint to send an SMS text to an {@link OtpUser}'s phone number with a verification code. This is used * during user signup (or if a user wishes to change their notification preferences to use a new un-verified phone diff --git a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java index aeb23d611..e722edb8c 100644 --- a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java +++ b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java @@ -2,8 +2,10 @@ import com.mongodb.client.model.Filters; import org.apache.logging.log4j.util.Strings; +import org.eclipse.jetty.http.HttpStatus; import org.opentripplanner.middleware.OtpMiddlewareMain; import org.opentripplanner.middleware.i18n.Message; +import org.opentripplanner.middleware.models.MobilityProfile; import org.opentripplanner.middleware.models.OtpUser; import org.opentripplanner.middleware.models.RelatedUser; import org.opentripplanner.middleware.persistence.Persistence; @@ -28,6 +30,7 @@ import static org.opentripplanner.middleware.tripmonitor.jobs.CheckMonitoredTrip.SETTINGS_PATH; import static org.opentripplanner.middleware.utils.I18nUtils.getLocaleFromString; import static org.opentripplanner.middleware.utils.I18nUtils.label; +import static org.opentripplanner.middleware.utils.JsonUtils.logMessageAndHalt; public class TrustedCompanion { @@ -42,10 +45,11 @@ private TrustedCompanion() { ConfigUtils.getConfigPropertyAsText("TRUSTED_COMPANION_CONFIRMATION_PAGE_URL"); public static final String ACCEPT_KEY = "acceptKey"; public static final String USER_LOCALE = "userLocale"; - public static final String EMAIL_FIELD_NAME = "email"; + public static final String EMAIL_PARAM = "email"; /** Note: This path is excluded from security checks, see {@link OtpMiddlewareMain#initializeHttpEndpoints()}. */ public static final String ACCEPT_DEPENDENT_PATH = "api/secure/user/acceptdependent"; + public static final String GET_DEPENDENT_MOBILITY_PROFILE_PATH = "/:%s/getdependentmobilityprofile"; /** * Accept a request from another user to be their dependent. This will include both companions and observers. If @@ -96,7 +100,7 @@ private static OtpUser getRelatedUserFromEmail(OtpUser dependentUser, String acc .stream() .filter(user -> user.acceptKey.equalsIgnoreCase(acceptKey)) .findFirst(); - return relatedUser.map(user -> Persistence.otpUsers.getOneFiltered(eq(EMAIL_FIELD_NAME, user.email))).orElse(null); + return relatedUser.map(user -> Persistence.otpUsers.getOneFiltered(eq(EMAIL_PARAM, user.email))).orElse(null); } /** @@ -154,7 +158,7 @@ public static void manageAcceptDependentEmail(OtpUser dependentUser, boolean isT .filter(relatedUser -> relatedUser.acceptKey == null) .forEach(relatedUser -> { String acceptKey = UUID.randomUUID().toString(); - OtpUser userToReceiveEmail = Persistence.otpUsers.getOneFiltered(eq(EMAIL_FIELD_NAME, relatedUser.email)); + OtpUser userToReceiveEmail = Persistence.otpUsers.getOneFiltered(eq(EMAIL_PARAM, relatedUser.email)); if (userToReceiveEmail != null && (isTest || sendAcceptDependentEmail(dependentUser, userToReceiveEmail, acceptKey))) { relatedUser.acceptKey = acceptKey; } @@ -229,10 +233,42 @@ public static void ensureRelatedUserIntegrity(OtpUser updatedUser, OtpUser preEx * Remove the dependent reference from the related user. */ public static void removeDependent(OtpUser dependent, RelatedUser relatedUser) { - OtpUser user = Persistence.otpUsers.getOneFiltered(eq(EMAIL_FIELD_NAME, relatedUser.email)); + OtpUser user = Persistence.otpUsers.getOneFiltered(eq(EMAIL_PARAM, relatedUser.email)); if (user != null) { user.dependents.remove(dependent.id); Persistence.otpUsers.replace(user.id, user); } } -} + + /** + * Retrieve the mobility profile for a dependent providing the requesting user is a trusted companion. + */ + public static MobilityProfile getDependentMobilityProfile(Request request, Response response, OtpUser relatedUser) { + if (relatedUser == null) { + logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Related user not provided or unknown."); + } + + var dependentEmail = HttpUtils.getQueryParamFromRequest(request, EMAIL_PARAM, false); + if (dependentEmail == null) { + logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Required dependent email address not provided."); + } + + var dependentUser = Persistence.otpUsers.getOneFiltered(eq(EMAIL_PARAM, dependentEmail)); + if (dependentUser == null) { + logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Dependent user unknown."); + } + + if (relatedUser != null && dependentUser != null) { + if (!relatedUser.dependents.contains(dependentUser.id)) { + logMessageAndHalt( + request, + HttpStatus.FORBIDDEN_403, + String.format("Related user is not a trusted companion for %s!", dependentEmail) + ); + } else { + return dependentUser.mobilityProfile; + } + } + return null; + } +} \ No newline at end of file diff --git a/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java b/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java index 1f62260db..689e42c73 100644 --- a/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java +++ b/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java @@ -9,6 +9,7 @@ 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.MobilityProfile; import org.opentripplanner.middleware.models.OtpUser; import org.opentripplanner.middleware.models.RelatedUser; import org.opentripplanner.middleware.persistence.Persistence; @@ -22,6 +23,7 @@ import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.Set; import java.util.UUID; import java.util.stream.Stream; @@ -29,13 +31,12 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assumptions.assumeTrue; - +import static org.opentripplanner.middleware.auth.Auth0Connection.restoreDefaultAuthDisabled; +import static org.opentripplanner.middleware.auth.Auth0Connection.setAuthDisabled; import static org.opentripplanner.middleware.testutils.ApiTestUtils.getMockHeaders; import static org.opentripplanner.middleware.testutils.ApiTestUtils.makeGetRequest; import static org.opentripplanner.middleware.testutils.ApiTestUtils.makeRequest; import static org.opentripplanner.middleware.testutils.ApiTestUtils.mockAuthenticatedGet; -import static org.opentripplanner.middleware.auth.Auth0Connection.restoreDefaultAuthDisabled; -import static org.opentripplanner.middleware.auth.Auth0Connection.setAuthDisabled; import static org.opentripplanner.middleware.testutils.PersistenceTestUtils.deleteOtpUser; public class OtpUserControllerTest extends OtpMiddlewareTestEnvironment { @@ -241,14 +242,8 @@ void canRemoveRelatedUserOnDelete() { @Test void canRemoveUserFromRelatedUsersList() throws Exception { setAuthDisabled(true); - relatedUserFour.dependents.add(dependentUserFour.id); - Persistence.otpUsers.replace(relatedUserFour.id, relatedUserFour); - dependentUserFour.relatedUsers.add(new RelatedUser( - relatedUserFour.email, - RelatedUser.RelatedUserStatus.CONFIRMED, - nickname - )); - Persistence.otpUsers.replace(dependentUserFour.id, dependentUserFour); + + createTrustedCompanionship(relatedUserFour, dependentUserFour); // Remove the first related user. dependentUserFour.relatedUsers.clear(); @@ -275,4 +270,45 @@ void canRemoveUserFromRelatedUsersList() throws Exception { setAuthDisabled(false); } + + @Test + void canGetDependentMobilityProfile() throws Exception { + setAuthDisabled(true); + + String path = String.format( + "api/secure/user/%s/getdependentmobilityprofile?email=%s", + relatedUserFour.id, + dependentUserFour.email + ); + + HttpResponseValues responseValues = makeGetRequest(path, getMockHeaders(relatedUserFour)); + assertEquals(HttpStatus.FORBIDDEN_403, responseValues.status); + + var mobilityProfile = new MobilityProfile(); + mobilityProfile.mobilityDevices = Set.of("service animal", "electric wheelchair", "white cane"); + mobilityProfile.updateMobilityMode(); + dependentUserFour.mobilityProfile = mobilityProfile; + + createTrustedCompanionship(relatedUserFour, dependentUserFour); + + responseValues = makeGetRequest(path, getMockHeaders(relatedUserFour)); + assertEquals(HttpStatus.OK_200, responseValues.status); + assertEquals(JsonUtils.toJson(mobilityProfile), responseValues.responseBody); + + setAuthDisabled(false); + } + + /** + * Create trusted companion relationship. + */ + private static void createTrustedCompanionship(OtpUser relatedUser, OtpUser dependentUser) { + relatedUser.dependents.add(dependentUser.id); + Persistence.otpUsers.replace(relatedUser.id, relatedUser); + dependentUser.relatedUsers.add(new RelatedUser( + relatedUser.email, + RelatedUser.RelatedUserStatus.CONFIRMED, + nickname + )); + Persistence.otpUsers.replace(dependentUser.id, dependentUser); + } } From 8a80cb29dfac86e22fb147981b93e44e4c90c719 Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Wed, 6 Nov 2024 15:33:25 +0000 Subject: [PATCH 2/8] chore(Updated Swagger docs): --- .../latest-spark-swagger-output.yaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/main/resources/latest-spark-swagger-output.yaml b/src/main/resources/latest-spark-swagger-output.yaml index 7a9098fb2..a229bb08e 100644 --- a/src/main/resources/latest-spark-swagger-output.yaml +++ b/src/main/resources/latest-spark-swagger-output.yaml @@ -1675,6 +1675,45 @@ paths: description: "An error occurred while performing the request. Contact an\ \ API administrator for more information." examples: {} + /api/secure/user/{id}/getdependentmobilityprofile: + get: + tags: + - "api/secure/user" + description: "Retrieve a dependent's mobility profile." + parameters: + - name: "id" + in: "path" + description: "The id of the related user." + required: true + type: "string" + responses: + "200": + description: "Successful operation" + examples: {} + schema: + $ref: "#/definitions/MobilityProfile" + responseSchema: + $ref: "#/definitions/MobilityProfile" + "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/{id}/verify_sms/{phoneNumber}: get: tags: From 3f5f7349fb1354b33c321ec510585e7fe9db65d5 Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Fri, 8 Nov 2024 09:55:05 +0000 Subject: [PATCH 3/8] refactor(PR feedback): Addressed issues with auth and dependent user reference --- .../controllers/api/OtpUserController.java | 18 ++++-------------- .../middleware/models/OtpUser.java | 2 +- .../tripmonitor/TrustedCompanion.java | 17 ++++++++++------- .../latest-spark-swagger-output.yaml | 9 ++------- .../api/OtpUserControllerTest.java | 19 +++++++++++++------ 5 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java b/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java index c1445e513..ff3e43168 100644 --- a/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java +++ b/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java @@ -26,8 +26,7 @@ import static io.github.manusant.ss.descriptor.MethodDescriptor.path; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.ACCEPT_KEY; -import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.EMAIL_PARAM; -import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.GET_DEPENDENT_MOBILITY_PROFILE_PATH; +import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.DEPENDENT_USER_ID; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.USER_LOCALE; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.ensureRelatedUserIntegrity; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.manageAcceptDependentEmail; @@ -103,13 +102,12 @@ protected void buildEndpoint(ApiEndpoint baseEndpoint) { .withResponseType(OtpUser.class), TrustedCompanion::acceptDependent ) - .get(path(ROOT_ROUTE + String.format(GET_DEPENDENT_MOBILITY_PROFILE_PATH, ID_PARAM)) + .get(path(ROOT_ROUTE + "/getdependentmobilityprofile") .withDescription("Retrieve a dependent's mobility profile.") .withResponses(SwaggerUtils.createStandardResponses(MobilityProfile.class)) - .withPathParam().withName(ID_PARAM).withRequired(true).withDescription("The id of the related user.").and() - .withPathParam().withName(EMAIL_PARAM).withRequired(true).withDescription("The dependent's email address.").and() + .withPathParam().withName(DEPENDENT_USER_ID).withRequired(true).withDescription("A dependent's user id.").and() .withResponseType(MobilityProfile.class), - this::getDependentMobilityProfile, JsonUtils::toJson + TrustedCompanion::getDependentMobilityProfile, JsonUtils::toJson ) .get(path(ROOT_ROUTE + String.format(VERIFY_ROUTE_TEMPLATE, ID_PARAM, VERIFY_PATH, PHONE_PARAM)) .withDescription("Request an SMS verification to be sent to an OtpUser's phone number.") @@ -139,14 +137,6 @@ protected OtpUser getUserProfile(RequestingUser profile) { return otpUser; } - /** - * Extract the related user from the request and return a dependent's mobility profile if the right conditions - * are met. - */ - private MobilityProfile getDependentMobilityProfile(Request request, Response response) { - return TrustedCompanion.getDependentMobilityProfile(request, response, getEntityForId(request, response)); - } - /** * HTTP endpoint to send an SMS text to an {@link OtpUser}'s phone number with a verification code. This is used * during user signup (or if a user wishes to change their notification preferences to use a new un-verified phone diff --git a/src/main/java/org/opentripplanner/middleware/models/OtpUser.java b/src/main/java/org/opentripplanner/middleware/models/OtpUser.java index 79de4104c..d9d798ecd 100644 --- a/src/main/java/org/opentripplanner/middleware/models/OtpUser.java +++ b/src/main/java/org/opentripplanner/middleware/models/OtpUser.java @@ -90,7 +90,7 @@ public enum Notification { /** Companions and observers of this user. */ public List relatedUsers = new ArrayList<>(); - /** Users that are dependent on this user. */ + /** A list of users (their ids only) that are dependent on this user. */ public List dependents = new ArrayList<>(); /** This user's name */ diff --git a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java index e722edb8c..2b1285b53 100644 --- a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java +++ b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java @@ -4,6 +4,7 @@ import org.apache.logging.log4j.util.Strings; import org.eclipse.jetty.http.HttpStatus; import org.opentripplanner.middleware.OtpMiddlewareMain; +import org.opentripplanner.middleware.auth.Auth0Connection; import org.opentripplanner.middleware.i18n.Message; import org.opentripplanner.middleware.models.MobilityProfile; import org.opentripplanner.middleware.models.OtpUser; @@ -46,10 +47,10 @@ private TrustedCompanion() { public static final String ACCEPT_KEY = "acceptKey"; public static final String USER_LOCALE = "userLocale"; public static final String EMAIL_PARAM = "email"; + public static final String DEPENDENT_USER_ID = "dependentuserid"; /** Note: This path is excluded from security checks, see {@link OtpMiddlewareMain#initializeHttpEndpoints()}. */ public static final String ACCEPT_DEPENDENT_PATH = "api/secure/user/acceptdependent"; - public static final String GET_DEPENDENT_MOBILITY_PROFILE_PATH = "/:%s/getdependentmobilityprofile"; /** * Accept a request from another user to be their dependent. This will include both companions and observers. If @@ -243,17 +244,19 @@ public static void removeDependent(OtpUser dependent, RelatedUser relatedUser) { /** * Retrieve the mobility profile for a dependent providing the requesting user is a trusted companion. */ - public static MobilityProfile getDependentMobilityProfile(Request request, Response response, OtpUser relatedUser) { + public static MobilityProfile getDependentMobilityProfile(Request request, Response response) { + OtpUser relatedUser = Auth0Connection.getUserFromRequest(request).otpUser; + if (relatedUser == null) { logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Related user not provided or unknown."); } - var dependentEmail = HttpUtils.getQueryParamFromRequest(request, EMAIL_PARAM, false); - if (dependentEmail == null) { - logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Required dependent email address not provided."); + var dependentUserId = HttpUtils.getQueryParamFromRequest(request, DEPENDENT_USER_ID, false); + if (dependentUserId == null) { + logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Required dependent id not provided."); } - var dependentUser = Persistence.otpUsers.getOneFiltered(eq(EMAIL_PARAM, dependentEmail)); + var dependentUser = Persistence.otpUsers.getById(dependentUserId); if (dependentUser == null) { logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Dependent user unknown."); } @@ -263,7 +266,7 @@ public static MobilityProfile getDependentMobilityProfile(Request request, Respo logMessageAndHalt( request, HttpStatus.FORBIDDEN_403, - String.format("Related user is not a trusted companion for %s!", dependentEmail) + String.format("Related user is not a trusted companion for dependent with id: %s!", dependentUserId) ); } else { return dependentUser.mobilityProfile; diff --git a/src/main/resources/latest-spark-swagger-output.yaml b/src/main/resources/latest-spark-swagger-output.yaml index a229bb08e..1e91844c1 100644 --- a/src/main/resources/latest-spark-swagger-output.yaml +++ b/src/main/resources/latest-spark-swagger-output.yaml @@ -1675,17 +1675,12 @@ paths: description: "An error occurred while performing the request. Contact an\ \ API administrator for more information." examples: {} - /api/secure/user/{id}/getdependentmobilityprofile: + /api/secure/user/getdependentmobilityprofile: get: tags: - "api/secure/user" description: "Retrieve a dependent's mobility profile." - parameters: - - name: "id" - in: "path" - description: "The id of the related user." - required: true - type: "string" + parameters: [] responses: "200": description: "Successful operation" diff --git a/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java b/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java index 689e42c73..e6589f861 100644 --- a/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java +++ b/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java @@ -1,5 +1,6 @@ package org.opentripplanner.middleware.controllers.api; +import com.auth0.json.mgmt.users.User; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; import org.junit.jupiter.api.AfterAll; @@ -33,11 +34,14 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue; import static org.opentripplanner.middleware.auth.Auth0Connection.restoreDefaultAuthDisabled; import static org.opentripplanner.middleware.auth.Auth0Connection.setAuthDisabled; +import static org.opentripplanner.middleware.auth.Auth0Users.createAuth0UserForEmail; +import static org.opentripplanner.middleware.testutils.ApiTestUtils.TEMP_AUTH0_USER_PASSWORD; import static org.opentripplanner.middleware.testutils.ApiTestUtils.getMockHeaders; import static org.opentripplanner.middleware.testutils.ApiTestUtils.makeGetRequest; import static org.opentripplanner.middleware.testutils.ApiTestUtils.makeRequest; import static org.opentripplanner.middleware.testutils.ApiTestUtils.mockAuthenticatedGet; import static org.opentripplanner.middleware.testutils.PersistenceTestUtils.deleteOtpUser; +import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.DEPENDENT_USER_ID; public class OtpUserControllerTest extends OtpMiddlewareTestEnvironment { private static final String INITIAL_PHONE_NUMBER = "+15555550222"; // Fake US 555 number. @@ -73,7 +77,13 @@ public static void setUp() throws Exception { dependentUserTwo = PersistenceTestUtils.createUser(ApiTestUtils.generateEmailAddress("dependent-two")); relatedUserThree = PersistenceTestUtils.createUser(ApiTestUtils.generateEmailAddress("related-user-three")); dependentUserThree = PersistenceTestUtils.createUser(ApiTestUtils.generateEmailAddress("dependent-three")); + relatedUserFour = PersistenceTestUtils.createUser(ApiTestUtils.generateEmailAddress("related-user-four")); + + User auth0User = createAuth0UserForEmail(relatedUserFour.email, TEMP_AUTH0_USER_PASSWORD); + relatedUserFour.auth0UserId = auth0User.getId(); + Persistence.otpUsers.replace(relatedUserFour.id, relatedUserFour); + dependentUserFour = PersistenceTestUtils.createUser(ApiTestUtils.generateEmailAddress("dependent-four")); } @@ -273,12 +283,10 @@ void canRemoveUserFromRelatedUsersList() throws Exception { @Test void canGetDependentMobilityProfile() throws Exception { - setAuthDisabled(true); - String path = String.format( - "api/secure/user/%s/getdependentmobilityprofile?email=%s", - relatedUserFour.id, - dependentUserFour.email + "api/secure/user/getdependentmobilityprofile?%s=%s", + DEPENDENT_USER_ID, + dependentUserFour.id ); HttpResponseValues responseValues = makeGetRequest(path, getMockHeaders(relatedUserFour)); @@ -295,7 +303,6 @@ void canGetDependentMobilityProfile() throws Exception { assertEquals(HttpStatus.OK_200, responseValues.status); assertEquals(JsonUtils.toJson(mobilityProfile), responseValues.responseBody); - setAuthDisabled(false); } /** From 665fd20355b31d595803b3ebee151d5fb5b05e06 Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Fri, 8 Nov 2024 10:11:18 +0000 Subject: [PATCH 4/8] refactor(TrustedCompanion.java): Minor changes to param name and messaging --- .../middleware/tripmonitor/TrustedCompanion.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java index 2b1285b53..0763da317 100644 --- a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java +++ b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java @@ -46,7 +46,7 @@ private TrustedCompanion() { ConfigUtils.getConfigPropertyAsText("TRUSTED_COMPANION_CONFIRMATION_PAGE_URL"); public static final String ACCEPT_KEY = "acceptKey"; public static final String USER_LOCALE = "userLocale"; - public static final String EMAIL_PARAM = "email"; + public static final String EMAIL_FIELD_NAME = "email"; public static final String DEPENDENT_USER_ID = "dependentuserid"; /** Note: This path is excluded from security checks, see {@link OtpMiddlewareMain#initializeHttpEndpoints()}. */ @@ -101,7 +101,7 @@ private static OtpUser getRelatedUserFromEmail(OtpUser dependentUser, String acc .stream() .filter(user -> user.acceptKey.equalsIgnoreCase(acceptKey)) .findFirst(); - return relatedUser.map(user -> Persistence.otpUsers.getOneFiltered(eq(EMAIL_PARAM, user.email))).orElse(null); + return relatedUser.map(user -> Persistence.otpUsers.getOneFiltered(eq(EMAIL_FIELD_NAME, user.email))).orElse(null); } /** @@ -159,7 +159,7 @@ public static void manageAcceptDependentEmail(OtpUser dependentUser, boolean isT .filter(relatedUser -> relatedUser.acceptKey == null) .forEach(relatedUser -> { String acceptKey = UUID.randomUUID().toString(); - OtpUser userToReceiveEmail = Persistence.otpUsers.getOneFiltered(eq(EMAIL_PARAM, relatedUser.email)); + OtpUser userToReceiveEmail = Persistence.otpUsers.getOneFiltered(eq(EMAIL_FIELD_NAME, relatedUser.email)); if (userToReceiveEmail != null && (isTest || sendAcceptDependentEmail(dependentUser, userToReceiveEmail, acceptKey))) { relatedUser.acceptKey = acceptKey; } @@ -234,7 +234,7 @@ public static void ensureRelatedUserIntegrity(OtpUser updatedUser, OtpUser preEx * Remove the dependent reference from the related user. */ public static void removeDependent(OtpUser dependent, RelatedUser relatedUser) { - OtpUser user = Persistence.otpUsers.getOneFiltered(eq(EMAIL_PARAM, relatedUser.email)); + OtpUser user = Persistence.otpUsers.getOneFiltered(eq(EMAIL_FIELD_NAME, relatedUser.email)); if (user != null) { user.dependents.remove(dependent.id); Persistence.otpUsers.replace(user.id, user); @@ -245,7 +245,7 @@ public static void removeDependent(OtpUser dependent, RelatedUser relatedUser) { * Retrieve the mobility profile for a dependent providing the requesting user is a trusted companion. */ public static MobilityProfile getDependentMobilityProfile(Request request, Response response) { - OtpUser relatedUser = Auth0Connection.getUserFromRequest(request).otpUser; + var relatedUser = Auth0Connection.getUserFromRequest(request).otpUser; if (relatedUser == null) { logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Related user not provided or unknown."); @@ -253,7 +253,7 @@ public static MobilityProfile getDependentMobilityProfile(Request request, Respo var dependentUserId = HttpUtils.getQueryParamFromRequest(request, DEPENDENT_USER_ID, false); if (dependentUserId == null) { - logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Required dependent id not provided."); + logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Required dependent's user id not provided."); } var dependentUser = Persistence.otpUsers.getById(dependentUserId); @@ -266,7 +266,7 @@ public static MobilityProfile getDependentMobilityProfile(Request request, Respo logMessageAndHalt( request, HttpStatus.FORBIDDEN_403, - String.format("Related user is not a trusted companion for dependent with id: %s!", dependentUserId) + String.format("Related user is not a trusted companion for dependent with user id: %s!", dependentUserId) ); } else { return dependentUser.mobilityProfile; From a355beb01dcf6024507734ce1a22b65a590bd3ca Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Fri, 8 Nov 2024 11:18:46 +0000 Subject: [PATCH 5/8] refactor(Updated to cover better object state checking): --- pom.xml | 7 +++++++ .../middleware/tripmonitor/TrustedCompanion.java | 11 +++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index d0131965f..26fce5f3e 100644 --- a/pom.xml +++ b/pom.xml @@ -125,6 +125,13 @@ 2.7 + + + org.apache.commons + commons-lang3 + 3.17.0 + + org.slf4j diff --git a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java index 0763da317..1ec4eaffe 100644 --- a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java +++ b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java @@ -1,6 +1,7 @@ package org.opentripplanner.middleware.tripmonitor; import com.mongodb.client.model.Filters; +import org.apache.commons.lang3.ObjectUtils; import org.apache.logging.log4j.util.Strings; import org.eclipse.jetty.http.HttpStatus; import org.opentripplanner.middleware.OtpMiddlewareMain; @@ -28,6 +29,8 @@ import static com.mongodb.client.model.Filters.eq; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.commons.lang3.ObjectUtils.isEmpty; +import static org.apache.commons.lang3.ObjectUtils.isNotEmpty; import static org.opentripplanner.middleware.tripmonitor.jobs.CheckMonitoredTrip.SETTINGS_PATH; import static org.opentripplanner.middleware.utils.I18nUtils.getLocaleFromString; import static org.opentripplanner.middleware.utils.I18nUtils.label; @@ -247,21 +250,21 @@ public static void removeDependent(OtpUser dependent, RelatedUser relatedUser) { public static MobilityProfile getDependentMobilityProfile(Request request, Response response) { var relatedUser = Auth0Connection.getUserFromRequest(request).otpUser; - if (relatedUser == null) { + if (isEmpty(relatedUser)) { logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Related user not provided or unknown."); } var dependentUserId = HttpUtils.getQueryParamFromRequest(request, DEPENDENT_USER_ID, false); - if (dependentUserId == null) { + if (isEmpty(dependentUserId)) { logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Required dependent's user id not provided."); } var dependentUser = Persistence.otpUsers.getById(dependentUserId); - if (dependentUser == null) { + if (isEmpty(dependentUser)) { logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Dependent user unknown."); } - if (relatedUser != null && dependentUser != null) { + if (isNotEmpty(relatedUser) && isNotEmpty(dependentUser)) { if (!relatedUser.dependents.contains(dependentUser.id)) { logMessageAndHalt( request, From deb32264726a15f90fe4a569c41c43f1113d74c5 Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Mon, 11 Nov 2024 14:14:02 +0000 Subject: [PATCH 6/8] refactor(Update to process multiple users and their lite mobility profile): --- .../controllers/api/OtpUserController.java | 12 ++-- .../models/MobilityProfileLite.java | 37 +++++++++++ .../tripmonitor/TrustedCompanion.java | 65 +++++++++++++------ .../latest-spark-swagger-output.yaml | 7 +- .../api/OtpUserControllerTest.java | 14 ++-- 5 files changed, 100 insertions(+), 35 deletions(-) create mode 100644 src/main/java/org/opentripplanner/middleware/models/MobilityProfileLite.java diff --git a/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java b/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java index ff3e43168..fdde0ef11 100644 --- a/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java +++ b/src/main/java/org/opentripplanner/middleware/controllers/api/OtpUserController.java @@ -7,7 +7,7 @@ import org.eclipse.jetty.http.HttpStatus; import org.opentripplanner.middleware.auth.Auth0Connection; import org.opentripplanner.middleware.auth.RequestingUser; -import org.opentripplanner.middleware.models.MobilityProfile; +import org.opentripplanner.middleware.models.MobilityProfileLite; import org.opentripplanner.middleware.models.OtpUser; import org.opentripplanner.middleware.persistence.Persistence; import org.opentripplanner.middleware.tripmonitor.TrustedCompanion; @@ -26,7 +26,7 @@ import static io.github.manusant.ss.descriptor.MethodDescriptor.path; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.ACCEPT_KEY; -import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.DEPENDENT_USER_ID; +import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.DEPENDENT_USER_IDS; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.USER_LOCALE; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.ensureRelatedUserIntegrity; import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.manageAcceptDependentEmail; @@ -103,10 +103,10 @@ protected void buildEndpoint(ApiEndpoint baseEndpoint) { TrustedCompanion::acceptDependent ) .get(path(ROOT_ROUTE + "/getdependentmobilityprofile") - .withDescription("Retrieve a dependent's mobility profile.") - .withResponses(SwaggerUtils.createStandardResponses(MobilityProfile.class)) - .withPathParam().withName(DEPENDENT_USER_ID).withRequired(true).withDescription("A dependent's user id.").and() - .withResponseType(MobilityProfile.class), + .withDescription("Retrieve the mobility profile for each valid dependent user id provided.") + .withResponses(SwaggerUtils.createStandardResponses(MobilityProfileLite.class)) + .withPathParam().withName(DEPENDENT_USER_IDS).withRequired(true).withDescription("A comma separated list of dependent user ids.").and() + .withResponseAsCollection(MobilityProfileLite.class), TrustedCompanion::getDependentMobilityProfile, JsonUtils::toJson ) .get(path(ROOT_ROUTE + String.format(VERIFY_ROUTE_TEMPLATE, ID_PARAM, VERIFY_PATH, PHONE_PARAM)) diff --git a/src/main/java/org/opentripplanner/middleware/models/MobilityProfileLite.java b/src/main/java/org/opentripplanner/middleware/models/MobilityProfileLite.java new file mode 100644 index 000000000..ff7f58859 --- /dev/null +++ b/src/main/java/org/opentripplanner/middleware/models/MobilityProfileLite.java @@ -0,0 +1,37 @@ +package org.opentripplanner.middleware.models; + +import java.util.Objects; + +public class MobilityProfileLite { + public String userId; + public String mobilityMode; + public String email; + public String name; + + public MobilityProfileLite() { + } + + public MobilityProfileLite(OtpUser user) { + this.userId = user.id; + this.mobilityMode = (user.mobilityProfile != null) ? user.mobilityProfile.mobilityMode : null; + this.email = user.email; + this.name = user.name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MobilityProfileLite that = (MobilityProfileLite) o; + return + Objects.equals(userId, that.userId) && + Objects.equals(mobilityMode, that.mobilityMode) && + Objects.equals(email, that.email) && + Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(userId, mobilityMode, email, name); + } +} diff --git a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java index 1ec4eaffe..aab3fc65a 100644 --- a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java +++ b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java @@ -1,13 +1,13 @@ package org.opentripplanner.middleware.tripmonitor; +import com.mongodb.client.FindIterable; import com.mongodb.client.model.Filters; -import org.apache.commons.lang3.ObjectUtils; import org.apache.logging.log4j.util.Strings; import org.eclipse.jetty.http.HttpStatus; import org.opentripplanner.middleware.OtpMiddlewareMain; import org.opentripplanner.middleware.auth.Auth0Connection; import org.opentripplanner.middleware.i18n.Message; -import org.opentripplanner.middleware.models.MobilityProfile; +import org.opentripplanner.middleware.models.MobilityProfileLite; import org.opentripplanner.middleware.models.OtpUser; import org.opentripplanner.middleware.models.RelatedUser; import org.opentripplanner.middleware.persistence.Persistence; @@ -19,6 +19,9 @@ import spark.Response; import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -50,7 +53,7 @@ private TrustedCompanion() { public static final String ACCEPT_KEY = "acceptKey"; public static final String USER_LOCALE = "userLocale"; public static final String EMAIL_FIELD_NAME = "email"; - public static final String DEPENDENT_USER_ID = "dependentuserid"; + public static final String DEPENDENT_USER_IDS = "dependentuserids"; /** Note: This path is excluded from security checks, see {@link OtpMiddlewareMain#initializeHttpEndpoints()}. */ public static final String ACCEPT_DEPENDENT_PATH = "api/secure/user/acceptdependent"; @@ -247,34 +250,54 @@ public static void removeDependent(OtpUser dependent, RelatedUser relatedUser) { /** * Retrieve the mobility profile for a dependent providing the requesting user is a trusted companion. */ - public static MobilityProfile getDependentMobilityProfile(Request request, Response response) { + public static List getDependentMobilityProfile(Request request, Response response) { var relatedUser = Auth0Connection.getUserFromRequest(request).otpUser; if (isEmpty(relatedUser)) { logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Related user not provided or unknown."); } - var dependentUserId = HttpUtils.getQueryParamFromRequest(request, DEPENDENT_USER_ID, false); - if (isEmpty(dependentUserId)) { - logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Required dependent's user id not provided."); + var dependentUserIds = HttpUtils.getQueryParamFromRequest(request, DEPENDENT_USER_IDS, false); + if (isEmpty(dependentUserIds)) { + logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Required list of dependent user ids not provided."); } - var dependentUser = Persistence.otpUsers.getById(dependentUserId); - if (isEmpty(dependentUser)) { - logMessageAndHalt(request, HttpStatus.BAD_REQUEST_400, "Dependent user unknown."); + var validDependentUserIds = getValidDependents(relatedUser, dependentUserIds); + if (validDependentUserIds.isEmpty()) { + logMessageAndHalt( + request, + HttpStatus.FORBIDDEN_403, + "Related user is not a trusted companion of any provided dependents!" + ); } - if (isNotEmpty(relatedUser) && isNotEmpty(dependentUser)) { - if (!relatedUser.dependents.contains(dependentUser.id)) { - logMessageAndHalt( - request, - HttpStatus.FORBIDDEN_403, - String.format("Related user is not a trusted companion for dependent with user id: %s!", dependentUserId) - ); - } else { - return dependentUser.mobilityProfile; - } + if (isNotEmpty(relatedUser) && !validDependentUserIds.isEmpty()) { + List profiles = new ArrayList<>(); + FindIterable validDependentUsers = Persistence + .otpUsers + .getFiltered(Filters.in("_id", validDependentUserIds)); + validDependentUsers.forEach(user -> profiles.add(new MobilityProfileLite(user))); + return profiles; } - return null; + return Collections.emptyList(); + } + + /** + * From the list of dependent user ids, extract all that have the related user as their trusted companion. + */ + private static List getValidDependents(OtpUser relatedUser, String dependentUserIds) { + // In case only one user id is provided with no comma. + String[] userIds = (dependentUserIds.contains(",")) + ? dependentUserIds.split(",") + : new String[]{dependentUserIds}; + + if (isEmpty(userIds)) { + return Collections.emptyList(); + } + + return Arrays + .stream(userIds) + .filter(userId -> relatedUser.dependents.contains(userId)) + .collect(Collectors.toList()); } } \ No newline at end of file diff --git a/src/main/resources/latest-spark-swagger-output.yaml b/src/main/resources/latest-spark-swagger-output.yaml index 1e91844c1..5890437f7 100644 --- a/src/main/resources/latest-spark-swagger-output.yaml +++ b/src/main/resources/latest-spark-swagger-output.yaml @@ -1679,16 +1679,17 @@ paths: get: tags: - "api/secure/user" - description: "Retrieve a dependent's mobility profile." + description: "Retrieve the mobility profile for each valid dependent user id\ + \ provided." parameters: [] responses: "200": description: "Successful operation" examples: {} schema: - $ref: "#/definitions/MobilityProfile" + $ref: "#/definitions/MobilityProfileLite" responseSchema: - $ref: "#/definitions/MobilityProfile" + $ref: "#/definitions/MobilityProfileLite" "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\ diff --git a/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java b/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java index e6589f861..a1d9f0c9e 100644 --- a/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java +++ b/src/test/java/org/opentripplanner/middleware/controllers/api/OtpUserControllerTest.java @@ -11,6 +11,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.opentripplanner.middleware.models.MobilityProfile; +import org.opentripplanner.middleware.models.MobilityProfileLite; import org.opentripplanner.middleware.models.OtpUser; import org.opentripplanner.middleware.models.RelatedUser; import org.opentripplanner.middleware.persistence.Persistence; @@ -41,7 +42,7 @@ import static org.opentripplanner.middleware.testutils.ApiTestUtils.makeRequest; import static org.opentripplanner.middleware.testutils.ApiTestUtils.mockAuthenticatedGet; import static org.opentripplanner.middleware.testutils.PersistenceTestUtils.deleteOtpUser; -import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.DEPENDENT_USER_ID; +import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.DEPENDENT_USER_IDS; public class OtpUserControllerTest extends OtpMiddlewareTestEnvironment { private static final String INITIAL_PHONE_NUMBER = "+15555550222"; // Fake US 555 number. @@ -284,8 +285,9 @@ void canRemoveUserFromRelatedUsersList() throws Exception { @Test void canGetDependentMobilityProfile() throws Exception { String path = String.format( - "api/secure/user/getdependentmobilityprofile?%s=%s", - DEPENDENT_USER_ID, + "api/secure/user/getdependentmobilityprofile?%s=%s,%s", + DEPENDENT_USER_IDS, + dependentUserThree.id, dependentUserFour.id ); @@ -296,13 +298,15 @@ void canGetDependentMobilityProfile() throws Exception { mobilityProfile.mobilityDevices = Set.of("service animal", "electric wheelchair", "white cane"); mobilityProfile.updateMobilityMode(); dependentUserFour.mobilityProfile = mobilityProfile; + dependentUserFour.name = "dependent-user-four-name"; createTrustedCompanionship(relatedUserFour, dependentUserFour); responseValues = makeGetRequest(path, getMockHeaders(relatedUserFour)); assertEquals(HttpStatus.OK_200, responseValues.status); - assertEquals(JsonUtils.toJson(mobilityProfile), responseValues.responseBody); - + List mobilityProfileLites = JsonUtils.getPOJOFromJSONAsList(responseValues.responseBody, MobilityProfileLite.class); + assert mobilityProfileLites != null; + assertEquals(new MobilityProfileLite(dependentUserFour), mobilityProfileLites.get(0)); } /** From 6f81abb30fc9f2db003b95debee2eada9327b884 Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Tue, 12 Nov 2024 11:02:36 +0000 Subject: [PATCH 7/8] refactor(TrustedCompanion.java): Updated getValidDependents to use Set to remove duplicate user ids --- .../middleware/tripmonitor/TrustedCompanion.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java index aab3fc65a..cad8bb17b 100644 --- a/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java +++ b/src/main/java/org/opentripplanner/middleware/tripmonitor/TrustedCompanion.java @@ -27,6 +27,7 @@ import java.util.Locale; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; @@ -285,19 +286,19 @@ public static List getDependentMobilityProfile(Request requ /** * From the list of dependent user ids, extract all that have the related user as their trusted companion. */ - private static List getValidDependents(OtpUser relatedUser, String dependentUserIds) { + private static Set getValidDependents(OtpUser relatedUser, String dependentUserIds) { // In case only one user id is provided with no comma. - String[] userIds = (dependentUserIds.contains(",")) + String[] userIds = dependentUserIds.contains(",") ? dependentUserIds.split(",") - : new String[]{dependentUserIds}; + : new String[] { dependentUserIds }; if (isEmpty(userIds)) { - return Collections.emptyList(); + return Collections.emptySet(); } return Arrays .stream(userIds) .filter(userId -> relatedUser.dependents.contains(userId)) - .collect(Collectors.toList()); + .collect(Collectors.toSet()); } } \ No newline at end of file From f13af4053ddc69c4ea957db8618a789283a5ec81 Mon Sep 17 00:00:00 2001 From: Robin Beer Date: Thu, 14 Nov 2024 07:51:53 +0000 Subject: [PATCH 8/8] refactor(MobilityProfileLite.java): Updated check for null value --- .../middleware/models/MobilityProfileLite.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/middleware/models/MobilityProfileLite.java b/src/main/java/org/opentripplanner/middleware/models/MobilityProfileLite.java index ff7f58859..0f6268d0f 100644 --- a/src/main/java/org/opentripplanner/middleware/models/MobilityProfileLite.java +++ b/src/main/java/org/opentripplanner/middleware/models/MobilityProfileLite.java @@ -2,18 +2,21 @@ import java.util.Objects; +import static org.apache.commons.lang3.ObjectUtils.isNotEmpty; + public class MobilityProfileLite { public String userId; public String mobilityMode; public String email; public String name; + /** This no-arg constructor exists to make MongoDB happy. */ public MobilityProfileLite() { } public MobilityProfileLite(OtpUser user) { this.userId = user.id; - this.mobilityMode = (user.mobilityProfile != null) ? user.mobilityProfile.mobilityMode : null; + this.mobilityMode = isNotEmpty(user.mobilityProfile) ? user.mobilityProfile.mobilityMode : null; this.email = user.email; this.name = user.name; }