Skip to content

Commit

Permalink
fix(OtpUser): Delete companion/observer references upon user deletion.
Browse files Browse the repository at this point in the history
  • Loading branch information
binh-dam-ibigroup committed Dec 6, 2024
1 parent f44faf2 commit cb120c5
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 17 deletions.
22 changes: 16 additions & 6 deletions src/main/java/org/opentripplanner/middleware/models/OtpUser.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.invalidateRelatedUsers;
import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.removeCompanion;
import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.removeDependent;
import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.removeObserver;
import static org.opentripplanner.middleware.tripmonitor.TrustedCompanion.removePrimaryTraveler;

/**
Expand Down Expand Up @@ -145,12 +148,7 @@ public boolean delete(boolean deleteAuth0User) {
// If a related user, invalidate relationship with all dependents.
for (String userId : dependents) {
OtpUser dependent = Persistence.otpUsers.getById(userId);
if (dependent != null) {
for (RelatedUser relatedUser : dependent.relatedUsers) {
if (relatedUser.email.equals(this.email)) {
relatedUser.status = RelatedUser.RelatedUserStatus.INVALID;
}
}
if (dependent != null && invalidateRelatedUsers(email, dependent.relatedUsers)) {
Persistence.otpUsers.replace(dependent.id, dependent);
}
}
Expand All @@ -166,6 +164,18 @@ public boolean delete(boolean deleteAuth0User) {
.getFiltered(Filters.eq("primary.userId", id))
.forEach(trip -> removePrimaryTraveler(this, trip));

// If a companion user, invalidate relationship in trips where they are companions and observers.
// TODO: Should we alert the user who created the trip of the deletion?
Persistence.monitoredTrips
.getFiltered(Filters.eq("companion.email", email))
.forEach(trip -> removeCompanion(this, trip));

// If a companion user, invalidate relationship in trips where they are companions and observers.
// TODO: Should we alert the user who created the trip of the deletion?
Persistence.monitoredTrips
.getFiltered(Filters.eq("observers.email", email))
.forEach(trip -> removeObserver(this, trip));

return Persistence.otpUsers.removeById(this.id);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -255,11 +256,54 @@ public static void removeDependent(OtpUser dependent, RelatedUser relatedUser) {
public static void removePrimaryTraveler(OtpUser otpUser, MonitoredTrip trip) {
if (trip.primary != null && otpUser.id.equals(trip.primary.userId)) {
trip.primary = null;
// Recheck existence of record in Mongo in case trip got deleted since last Mongo query.
if (Persistence.monitoredTrips.getById(trip.id) != null) {
Persistence.monitoredTrips.replace(trip.id, trip);
}
Persistence.monitoredTrips.replace(trip.id, trip);
}
}

/**
* Remove the specified user as companion from the specified trip.
*/
public static void removeCompanion(OtpUser otpUser, MonitoredTrip trip) {
if (invalidateRelatedUser(otpUser.email, trip.companion)) {
Persistence.monitoredTrips.replace(trip.id, trip);
}
}

/**
* Remove the specified user as observer from the specified trip.
*/
public static void removeObserver(OtpUser otpUser, MonitoredTrip trip) {
if (invalidateRelatedUsers(otpUser.email, trip.observers)) {
Persistence.monitoredTrips.replace(trip.id, trip);
}
}

/**
* Helper to invalidate a RelatedUser (companion) relationship.
* @return true if the status changed to invalid, false otherwise.
*/
public static boolean invalidateRelatedUser(String email, RelatedUser relatedUser) {
if (
relatedUser != null &&
email.equals(relatedUser.email) &&
relatedUser.status == RelatedUser.RelatedUserStatus.CONFIRMED
) {
relatedUser.status = RelatedUser.RelatedUserStatus.INVALID;
return true;
}
return false;
}

/**
* Remove the specified user as observer from the specified trip.
* @return true if one or more related users gor invalidated, false otherwise.
*/
public static boolean invalidateRelatedUsers(String email, Collection<RelatedUser> relatedUsers) {
boolean hasChanged = false;
for (RelatedUser relatedUser : relatedUsers) {
hasChanged |= invalidateRelatedUser(email, relatedUser);
}
return hasChanged;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
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;
Expand Down Expand Up @@ -245,19 +246,45 @@ void canRemoveRelatedUserOnDelete() {
Persistence.otpUsers.replace(dependentUserThree.id, dependentUserThree);

// Create a monitored trip with dependentUserThree as primary traveler, relatedUserThree as companion.
MonitoredTrip trip = new MonitoredTrip();
trip.id = UUID.randomUUID().toString();
trip.primary = new MobilityProfileLite(dependentUserThree);
trip.companion = new RelatedUser(relatedUserThree.email, RelatedUser.RelatedUserStatus.CONFIRMED, "nickname");
Persistence.monitoredTrips.create(trip);
MonitoredTrip tripWithPrimaryTraveler = new MonitoredTrip();
tripWithPrimaryTraveler.id = UUID.randomUUID().toString();
tripWithPrimaryTraveler.userId = relatedUserThree.id;
tripWithPrimaryTraveler.primary = new MobilityProfileLite(dependentUserThree);
tripWithPrimaryTraveler.companion = new RelatedUser(
relatedUserThree.email,
RelatedUser.RelatedUserStatus.CONFIRMED,
"nickname"
);
Persistence.monitoredTrips.create(tripWithPrimaryTraveler);

// Create a monitored trip with dependentUserThree as companion and observer to relatedUserThree.
// (In practice, a user cannot be both a companion and observer.)
MonitoredTrip tripWithCompanionAndObserver = new MonitoredTrip();
tripWithCompanionAndObserver.id = UUID.randomUUID().toString();
tripWithCompanionAndObserver.userId = relatedUserThree.id;
tripWithCompanionAndObserver.companion = new RelatedUser(
dependentUserThree.email,
RelatedUser.RelatedUserStatus.CONFIRMED,
"nickname"
);
tripWithCompanionAndObserver.observers.add(tripWithCompanionAndObserver.companion);
Persistence.monitoredTrips.create(tripWithCompanionAndObserver);

dependentUserThree.delete(false);
relatedUserThree = Persistence.otpUsers.getById(relatedUserThree.id);
assertFalse(relatedUserThree.dependents.contains(dependentUserThree.id));

// If a dependent user deletes their profile, delete them from any trip where they are a dependent.
MonitoredTrip updatedTrip = Persistence.monitoredTrips.getById(trip.id);
assertNull(updatedTrip.primary);
MonitoredTrip updatedTripWithPrimaryTraveler = Persistence.monitoredTrips.getById(tripWithPrimaryTraveler.id);
assertNull(updatedTripWithPrimaryTraveler.primary);

// If a companion on a trip deletes their profile, invalidate them from any trip where they are a companion
// or an observer.
MonitoredTrip updatedTripWithCompanionAndObserver = Persistence.monitoredTrips.getById(tripWithCompanionAndObserver.id);
assertNotNull(updatedTripWithCompanionAndObserver.companion);
assertEquals(RelatedUser.RelatedUserStatus.INVALID, updatedTripWithCompanionAndObserver.companion.status);
assertFalse(updatedTripWithCompanionAndObserver.observers.isEmpty());
assertEquals(RelatedUser.RelatedUserStatus.INVALID, updatedTripWithCompanionAndObserver.observers.get(0).status);
}

/**
Expand Down

0 comments on commit cb120c5

Please sign in to comment.