• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DataBiosphere / consent / #6182

08 Jul 2025 07:04PM UTC coverage: 79.433% (+0.03%) from 79.402%
#6182

push

web-flow
DT-1934: Add Institution Domains (#2599)

109 of 119 new or added lines in 8 files covered. (91.6%)

10459 of 13167 relevant lines covered (79.43%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.7
/src/main/java/org/broadinstitute/consent/http/service/UserService.java
1
package org.broadinstitute.consent.http.service;
2

3
import static org.broadinstitute.consent.http.enumeration.UserFields.ERA_EXPIRATION_DATE;
4
import static org.broadinstitute.consent.http.enumeration.UserFields.ERA_STATUS;
5

6
import com.google.common.annotations.VisibleForTesting;
7
import com.google.gson.Gson;
8
import com.google.gson.JsonArray;
9
import com.google.gson.JsonElement;
10
import com.google.gson.JsonObject;
11
import com.google.inject.Inject;
12
import jakarta.ws.rs.BadRequestException;
13
import jakarta.ws.rs.NotFoundException;
14
import java.time.Instant;
15
import java.util.Collections;
16
import java.util.Date;
17
import java.util.List;
18
import java.util.Objects;
19
import java.util.stream.Stream;
20
import org.apache.commons.collections4.CollectionUtils;
21
import org.apache.commons.lang3.StringUtils;
22
import org.broadinstitute.consent.http.db.AcknowledgementDAO;
23
import org.broadinstitute.consent.http.db.DaaDAO;
24
import org.broadinstitute.consent.http.db.FileStorageObjectDAO;
25
import org.broadinstitute.consent.http.db.InstitutionDAO;
26
import org.broadinstitute.consent.http.db.LibraryCardDAO;
27
import org.broadinstitute.consent.http.db.SamDAO;
28
import org.broadinstitute.consent.http.db.UserDAO;
29
import org.broadinstitute.consent.http.db.UserPropertyDAO;
30
import org.broadinstitute.consent.http.db.UserRoleDAO;
31
import org.broadinstitute.consent.http.db.VoteDAO;
32
import org.broadinstitute.consent.http.enumeration.UserFields;
33
import org.broadinstitute.consent.http.enumeration.UserRoles;
34
import org.broadinstitute.consent.http.exceptions.ConsentConflictException;
35
import org.broadinstitute.consent.http.exceptions.LibraryCardRequiredException;
36
import org.broadinstitute.consent.http.models.AuthUser;
37
import org.broadinstitute.consent.http.models.DataAccessAgreement;
38
import org.broadinstitute.consent.http.models.Institution;
39
import org.broadinstitute.consent.http.models.LibraryCard;
40
import org.broadinstitute.consent.http.models.User;
41
import org.broadinstitute.consent.http.models.UserProperty;
42
import org.broadinstitute.consent.http.models.UserRole;
43
import org.broadinstitute.consent.http.models.UserUpdateFields;
44
import org.broadinstitute.consent.http.models.Vote;
45
import org.broadinstitute.consent.http.resources.Resource;
46
import org.broadinstitute.consent.http.service.dao.DraftServiceDAO;
47
import org.broadinstitute.consent.http.service.dao.UserServiceDAO;
48
import org.broadinstitute.consent.http.util.ConsentLogger;
49
import org.broadinstitute.consent.http.util.gson.GsonUtil;
50

51
public class UserService implements ConsentLogger {
52

53
  public static final String LIBRARY_CARD_FIELD = "libraryCard";
54
  public static final String LIBRARY_CARDS_FIELD = "libraryCards";
55
  public static final String USER_PROPERTIES_FIELD = "properties";
56
  public static final String USER_STATUS_INFO_FIELD = "userStatusInfo";
57

58
  private final UserPropertyDAO userPropertyDAO;
59
  private final UserDAO userDAO;
60
  private final UserRoleDAO userRoleDAO;
61
  private final VoteDAO voteDAO;
62
  private final InstitutionDAO institutionDAO;
63
  private final LibraryCardDAO libraryCardDAO;
64
  private final AcknowledgementDAO acknowledgementDAO;
65
  private final FileStorageObjectDAO fileStorageObjectDAO;
66
  private final SamDAO samDAO;
67
  private final UserServiceDAO userServiceDAO;
68
  private final DaaDAO daaDAO;
69
  private final DraftServiceDAO draftServiceDAO;
70
  private final InstitutionService institutionService;
71

72
  @Inject
73
  public UserService(UserDAO userDAO, UserPropertyDAO userPropertyDAO, UserRoleDAO userRoleDAO,
74
      VoteDAO voteDAO, InstitutionDAO institutionDAO, LibraryCardDAO libraryCardDAO,
75
      AcknowledgementDAO acknowledgementDAO, FileStorageObjectDAO fileStorageObjectDAO,
76
      SamDAO samDAO, UserServiceDAO userServiceDAO, DaaDAO daaDAO, DraftServiceDAO draftServiceDAO,
77
      InstitutionService institutionService) {
1✔
78
    this.userDAO = userDAO;
1✔
79
    this.userPropertyDAO = userPropertyDAO;
1✔
80
    this.userRoleDAO = userRoleDAO;
1✔
81
    this.voteDAO = voteDAO;
1✔
82
    this.institutionDAO = institutionDAO;
1✔
83
    this.libraryCardDAO = libraryCardDAO;
1✔
84
    this.acknowledgementDAO = acknowledgementDAO;
1✔
85
    this.fileStorageObjectDAO = fileStorageObjectDAO;
1✔
86
    this.samDAO = samDAO;
1✔
87
    this.userServiceDAO = userServiceDAO;
1✔
88
    this.daaDAO = daaDAO;
1✔
89
    this.draftServiceDAO = draftServiceDAO;
1✔
90
    this.institutionService = institutionService;
1✔
91
  }
1✔
92

93
  /**
94
   * Update a select group of user fields for a user id.
95
   *
96
   * @param userUpdateFields A UserUpdateFields object for all update information
97
   * @param userId           The User's ID
98
   * @return The updated User
99
   */
100
  public User updateUserFieldsById(UserUpdateFields userUpdateFields, Integer userId) {
101
    if (Objects.nonNull(userUpdateFields)) {
1✔
102
      // Update Primary User Fields
103
      if (Objects.nonNull(userUpdateFields.getDisplayName())) {
1✔
104
        userDAO.updateDisplayName(userId, userUpdateFields.getDisplayName());
1✔
105
      }
106
      if (Objects.nonNull(userUpdateFields.getInstitutionId())) {
1✔
107
        userDAO.updateInstitutionId(userId, userUpdateFields.getInstitutionId());
1✔
108
      }
109
      if (Objects.nonNull(userUpdateFields.getEmailPreference())) {
1✔
110
        userDAO.updateEmailPreference(userId, userUpdateFields.getEmailPreference());
1✔
111
      }
112
      if (Objects.nonNull(userUpdateFields.getEraCommonsId())) {
1✔
113
        userDAO.updateEraCommonsId(userId, userUpdateFields.getEraCommonsId());
1✔
114
      }
115

116
      // Update User Properties
117
      List<UserProperty> userProps = userUpdateFields.buildUserProperties(userId);
1✔
118
      if (!userProps.isEmpty()) {
1✔
119
        userPropertyDAO.deletePropertiesByUserAndKey(userProps);
1✔
120
        userPropertyDAO.insertAll(userProps);
1✔
121
      }
122

123
      // Handle Roles
124
      if (Objects.nonNull(userUpdateFields.getUserRoleIds())) {
1✔
125
        List<Integer> currentRoleIds = userRoleDAO.findRolesByUserId(userId).stream()
1✔
126
            .map(UserRole::getRoleId).toList();
1✔
127
        List<Integer> roleIdsToAdd = userUpdateFields.getRoleIdsToAdd(currentRoleIds);
1✔
128
        List<Integer> roleIdsToRemove = userUpdateFields.getRoleIdsToRemove(currentRoleIds);
1✔
129
        // Add the new role ids to the user
130
        if (!roleIdsToAdd.isEmpty()) {
1✔
131
          List<UserRole> newRoles = roleIdsToAdd.stream()
1✔
132
              .map(id -> new UserRole(id,
1✔
133
                  Objects.requireNonNull(UserRoles.getUserRoleFromId(id)).getRoleName()))
1✔
134
              .toList();
1✔
135
          userRoleDAO.insertUserRoles(newRoles, userId);
1✔
136
        }
137
        // Remove the old role ids from the user
138
        if (!roleIdsToRemove.isEmpty()) {
1✔
139
          userRoleDAO.removeUserRoles(userId, roleIdsToRemove);
1✔
140
        }
141
      }
142

143
    }
144
    return findUserById(userId);
1✔
145
  }
146

147
  public void insertRoleAndInstitutionForUser(UserRole role, User user) {
148
    var userId = user.getUserId();
1✔
149
    try {
150
      if (user.getInstitutionId() == null) {
1✔
151
        Institution institution = institutionService.findInstitutionForEmail(user.getEmail());
1✔
152
        if (institution == null) {
1✔
153
          throw new BadRequestException(
1✔
154
              "No institution found for user: %s".formatted(user.getEmail()));
1✔
155
        }
156
        userServiceDAO.insertRoleAndInstitutionTxn(role, institution.getId(), userId);
1✔
157
      } else {
1✔
158
        userRoleDAO.insertSingleUserRole(role.getRoleId(), userId);
1✔
159
      }
160
    } catch (Exception e) {
1✔
161
      logException(
1✔
162
          "Error when updating user: %s, role: %s".formatted(userId, role), e);
1✔
163
      throw e;
1✔
164
    }
1✔
165
  }
1✔
166

167
  public User createUser(User user) {
168
    // Default role is researcher.
169
    if (CollectionUtils.isEmpty(user.getRoles())) {
1✔
170
      user.setResearcherRole();
1✔
171
    }
172
    validateRequiredFields(user);
1✔
173
    User existingUser = userDAO.findUserByEmail(user.getEmail());
1✔
174
    if (Objects.nonNull(existingUser)) {
1✔
175
      throw new BadRequestException("User exists with this email address: " + user.getEmail());
1✔
176
    }
177
    Institution institution = institutionService.findInstitutionForEmail(user.getEmail());
1✔
178
    if (institution != null) {
1✔
179
      user.setInstitutionId(institution.getId());
1✔
180
    }
181
    Integer userId = userDAO.insertUser(user.getEmail(), user.getDisplayName(),
1✔
182
        user.getInstitutionId(), new Date());
1✔
183
    insertUserRoles(user.getRoles(), userId);
1✔
184
    assignExistingLibraryCardToUser(user);
1✔
185
    return userDAO.findUserById(userId);
1✔
186
  }
187

188
  public User findUserById(Integer id) throws NotFoundException {
189
    User user = userDAO.findUserById(id);
1✔
190
    if (user == null) {
1✔
191
      throw new NotFoundException("Unable to find user with id: " + id);
1✔
192
    }
193
    return user;
1✔
194
  }
195

196
  public User findUserByEmail(String email) throws NotFoundException {
197
    User user = userDAO.findUserByEmail(email);
1✔
198
    if (user == null) {
1✔
199
      throw new NotFoundException("Unable to find user with email: " + email);
1✔
200
    }
201
    return user;
1✔
202
  }
203

204
  /**
205
   * Find users as a specific role, e.g., Admins can see all users, other roles can only see a
206
   * subset of users.
207
   *
208
   * @param user     The user making the request
209
   * @param roleName The role the user is making the request as
210
   * @return List of Users for specified role name
211
   */
212
  public List<User> getUsersAsRole(User user, String roleName) {
213
    switch (roleName) {
1✔
214
      // SigningOfficial console is technically pulling LCs, it's just bringing associated users along for the ride
215
      // However LCs can be created for users not yet registered in the system
216
      // As such a more specialized query is needed to produce the proper listing
217
      case Resource.SIGNINGOFFICIAL:
218
        Integer institutionId = user.getInstitutionId();
1✔
219
        if (Objects.nonNull(user.getInstitutionId())) {
1✔
220
          return userDAO.getUsersFromInstitutionWithCards(institutionId);
1✔
221
        } else {
222
          throw new NotFoundException("Signing Official (user: " + user.getDisplayName()
1✔
223
              + ") is not associated with an Institution.");
224
        }
225
      case Resource.ADMIN:
226
        return userDAO.findUsersWithLCsAndInstitution();
1✔
227
      default:
228
        // do nothing
229
    }
230
    return Collections.emptyList();
×
231
  }
232

233
  public List<SimplifiedUser> getUsersByDaaId(Integer daaId) {
234
    if (Objects.isNull(daaId)) {
1✔
235
      throw new IllegalArgumentException();
×
236
    }
237
    DataAccessAgreement daa = daaDAO.findById(daaId);
1✔
238
    if (Objects.isNull(daa)) {
1✔
239
      throw new NotFoundException();
1✔
240
    }
241
    List<User> users = userDAO.getUsersWithCardsByDaaId(daaId);
1✔
242
    return users.stream().map(SimplifiedUser::new).toList();
1✔
243
  }
244

245
  public void deleteUserByEmail(String email) {
246
    User user = userDAO.findUserByEmail(email);
1✔
247
    if (user == null) {
1✔
248
      throw new NotFoundException("The user for the specified E-Mail address does not exist");
×
249
    }
250
    Integer userId = user.getUserId();
1✔
251
    List<Integer> roleIds = userRoleDAO.
1✔
252
        findRolesByUserId(userId).
1✔
253
        stream().
1✔
254
        map(UserRole::getRoleId).
1✔
255
        toList();
1✔
256
    if (!roleIds.isEmpty()) {
1✔
257
      userRoleDAO.removeUserRoles(userId, roleIds);
×
258
    }
259
    List<Vote> votes = voteDAO.findVotesByUserId(userId);
1✔
260
    if (!votes.isEmpty()) {
1✔
261
      List<Integer> voteIds = votes.stream().map(Vote::getVoteId).toList();
×
262
      voteDAO.removeVotesByIds(voteIds);
×
263
    }
264
    try {
265
      draftServiceDAO.deleteDraftsByUser(user);
1✔
266
    } catch (Exception e) {
×
267
      logException(
×
268
          String.format("Unable to delete all drafts and files for userId %d. Error was: %s",
×
269
              userId, e.getMessage()), e);
×
270
    }
1✔
271
    try {
272
      institutionDAO.deleteAllInstitutionsByUser(userId);
1✔
NEW
273
    } catch (Exception e) {
×
NEW
274
      logException(
×
NEW
275
          String.format("Unable to delete all institutions for userId %d. Error was: %s",
×
NEW
276
              userId, e.getMessage()), e);
×
277
    }
1✔
278
    userPropertyDAO.deleteAllPropertiesByUser(userId);
1✔
279
    libraryCardDAO.deleteAllLibraryCardsByUser(userId);
1✔
280
    acknowledgementDAO.deleteAllAcknowledgementsByUser(userId);
1✔
281
    fileStorageObjectDAO.deleteAllUserFiles(userId);
1✔
282
    userDAO.deleteUserById(userId);
1✔
283
  }
1✔
284

285
  public List<UserProperty> findAllUserProperties(Integer userId) {
286
    return userPropertyDAO.findUserPropertiesByUserIdAndPropertyKeys(userId,
1✔
287
        UserFields.getValues());
1✔
288
  }
289

290
  public void updateEmailPreference(boolean preference, Integer userId) {
291
    userDAO.updateEmailPreference(userId, preference);
×
292
  }
×
293

294
  public List<SimplifiedUser> findSOsByInstitutionId(Integer institutionId) {
295
    if (Objects.isNull(institutionId)) {
1✔
296
      return Collections.emptyList();
1✔
297
    }
298

299
    List<User> users = userDAO.getSOsByInstitution(institutionId);
1✔
300
    return users.stream().map(SimplifiedUser::new).toList();
1✔
301
  }
302

303
  public List<User> findUsersByInstitutionId(Integer institutionId) {
304
    if (Objects.isNull(institutionId)) {
1✔
305
      throw new IllegalArgumentException();
1✔
306
    }
307
    Institution institution = institutionDAO.findInstitutionById(institutionId);
1✔
308
    if (Objects.isNull(institution)) {
1✔
309
      throw new NotFoundException();
×
310
    }
311
    return userDAO.findUsersByInstitution(institutionId);
1✔
312
  }
313

314
  public void deleteUserRole(User authUser, Integer userId, Integer roleId) {
315
    userRoleDAO.removeSingleUserRole(userId, roleId);
×
316
    logInfo(
×
317
        "User %s deleted roleId: %s from User ID: %s".formatted(authUser.getDisplayName(), roleId,
×
318
            userId));
319
  }
×
320

321
  public List<User> findUsersWithNoInstitution() {
322
    return userDAO.getUsersWithNoInstitution();
1✔
323
  }
324

325
  /**
326
   * Convenience method to return a response-friendly json object of the user.
327
   *
328
   * @param authUser The AuthUser. Used to determine if we should return auth user properties
329
   * @param userId   The User. This is the user we want to return properties for
330
   * @return JsonObject.
331
   */
332
  public JsonObject findUserWithPropertiesByIdAsJsonObject(AuthUser authUser, Integer userId) {
333
    Gson gson = GsonUtil.getInstance();
1✔
334
    User user = findUserById(userId);
1✔
335
    List<UserProperty> props = findAllUserProperties(user.getUserId());
1✔
336
    JsonObject userJson = gson.toJsonTree(user).getAsJsonObject();
1✔
337
    JsonArray propsJson = gson.toJsonTree(props).getAsJsonArray();
1✔
338
    userJson.add(USER_PROPERTIES_FIELD, propsJson);
1✔
339
    if (user.getLibraryCard() != null) {
1✔
340
      JsonObject libraryCardJson = gson.toJsonTree(user.getLibraryCard()).getAsJsonObject();
1✔
341
      userJson.add(LIBRARY_CARD_FIELD, libraryCardJson);
1✔
342
      // Note that this is provided for backwards compatibility with the UI and will be removed
343
      userJson.add(LIBRARY_CARDS_FIELD, gson.toJsonTree(List.of(libraryCardJson)));
1✔
344
    }
345
    if (authUser.getEmail().equalsIgnoreCase(user.getEmail()) && Objects.nonNull(
1✔
346
        authUser.getUserStatusInfo())) {
1✔
347
      JsonObject userStatusInfoJson = gson.toJsonTree(authUser.getUserStatusInfo())
1✔
348
          .getAsJsonObject();
1✔
349
      userJson.add(USER_STATUS_INFO_FIELD, userStatusInfoJson);
1✔
350
    }
351
    return userJson;
1✔
352
  }
353

354
  private void validateRequiredFields(User user) {
355
    if (StringUtils.isEmpty(user.getDisplayName())) {
1✔
356
      throw new BadRequestException("Display Name cannot be empty");
1✔
357
    }
358
    if (StringUtils.isEmpty(user.getEmail())) {
1✔
359
      throw new BadRequestException("Email address cannot be empty");
1✔
360
    }
361
    List<String> validRoleNameList = Stream.of(UserRoles.RESEARCHER, UserRoles.ALUMNI,
1✔
362
        UserRoles.ADMIN).map(UserRoles::getRoleName).toList();
1✔
363
    user.getRoles().forEach(role -> {
1✔
364
      if (!validRoleNameList.contains(role.getName())) {
1✔
365
        String validRoleNames = String.join(", ", validRoleNameList);
1✔
366
        throw new BadRequestException(
1✔
367
            "Invalid role: " + role.getName() + ". Valid roles are: " + validRoleNames);
1✔
368
      }
369
    });
1✔
370
  }
1✔
371

372
  public void insertUserRoles(List<UserRole> roles, Integer userId) {
373
    roles.forEach(r -> {
1✔
374
      if (r.getRoleId() == null) {
1✔
375
        r.setRoleId(userRoleDAO.findRoleIdByName(r.getName()));
×
376
      }
377
    });
1✔
378
    userRoleDAO.insertUserRoles(roles, userId);
1✔
379
  }
1✔
380

381
  private void assignExistingLibraryCardToUser(User user) {
382
    LibraryCard libraryCard = libraryCardDAO.findLibraryCardByUserEmail(user.getEmail());
1✔
383
    if (libraryCard != null) {
1✔
384
      libraryCardDAO.updateLibraryCardById(
1✔
385
          libraryCard.getId(),
1✔
386
          user.getUserId(),
1✔
387
          user.getDisplayName(),
1✔
388
          user.getEmail(),
1✔
389
          user.getUserId(),
1✔
390
          new Date());
391
    }
392
  }
1✔
393

394
  public User findOrCreateUser(AuthUser authUser) throws Exception {
395
    User user;
396
    // Ensure that the user is a registered DUOS user
397
    try {
398
      user = userDAO.findUserByEmail(authUser.getEmail());
1✔
399
    } catch (NotFoundException nfe) {
1✔
400
      User newUser = new User();
1✔
401
      newUser.setEmail(authUser.getEmail());
1✔
402
      newUser.setDisplayName(authUser.getName());
1✔
403
      user = createUser(newUser);
1✔
404
    }
1✔
405
    // Ensure that the user is a registered SAM user
406
    try {
407
      samDAO.postRegistrationInfo(authUser);
1✔
408
    } catch (ConsentConflictException cce) {
×
409
      // no-op in the case of conflicts.
410
    }
1✔
411
    return user;
1✔
412
  }
413

414
  public List<User> findUsersInJsonArray(String json, String arrayKey) {
415
    List<JsonElement> jsonElementList;
416
    try {
417
      JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);
1✔
418
      jsonElementList = jsonObject.getAsJsonArray(arrayKey).asList();
1✔
419
    } catch (Exception e) {
1✔
420
      throw new BadRequestException("Invalid JSON or missing array with key: " + arrayKey);
1✔
421
    }
1✔
422
    return jsonElementList.stream().distinct().map(e -> findUserById(e.getAsInt())).toList();
1✔
423
  }
424

425
  public void validateActiveERACredentials(User user) {
426
    if (user.getLibraryCard() == null) {
1✔
427
      throw new LibraryCardRequiredException();
1✔
428
    }
429
    boolean hasEraCommonsId = user.getEraCommonsId() != null;
1✔
430
    if (!hasEraCommonsId) {
1✔
431
      throw new BadRequestException("User does not have an Era Commons ID");
1✔
432
    }
433
    List<UserProperty> userProperties = findAllUserProperties(user.getUserId());
1✔
434
    List<UserProperty> eraStatusProps = userProperties.stream().filter(
1✔
435
            userProperty -> userProperty.getPropertyKey().equalsIgnoreCase(ERA_STATUS.getValue()))
1✔
436
        .toList();
1✔
437
    List<UserProperty> eraExpirationProps = userProperties.stream().filter(
1✔
438
            userProperty -> userProperty.getPropertyKey()
1✔
439
                .equalsIgnoreCase(ERA_EXPIRATION_DATE.getValue()))
1✔
440
        .toList();
1✔
441
    if (eraStatusProps.size() == 1 && eraExpirationProps.size() == 1) {
1✔
442
      if (!eraStatusProps.get(0).getPropertyValue().equalsIgnoreCase("true")) {
1✔
443
        throw new BadRequestException("User does not have an Era Commons ID that is authorized.");
×
444
      }
445
      if (Instant.ofEpochMilli(Long.parseLong(eraExpirationProps.get(0).getPropertyValue()))
1✔
446
          .isBefore(Instant.now())) {
1✔
447
        throw new BadRequestException("User has an expired Era Commons ID.");
1✔
448
      }
449
    } else {
450
      throw new BadRequestException(
1✔
451
          "Invalid ERA configuration for this user.  Only one ERA Commons ID is allowed.");
452
    }
453
  }
1✔
454

455
  /**
456
   * Compliance method that implements a set of rules in order to ensure Library Card and
457
   * Institution matching rules are adhered to when authorizing users of the system.
458
   * @param email of the user being evaluated
459
   * @return user with the Institution and Library Card rules applied or null if the requestor isn't
460
   * a DUOS user.
461
   */
462
  public User enforceInstitutionAndLibraryCardRules(String email) {
463
    User user;
464
    Institution institutionFromEmail = institutionService.findInstitutionForEmail(email);
1✔
465
    try {
466
      user = findUserByEmail(email);
1✔
467
    } catch (NotFoundException nfe) {
×
468
      return null;
×
469
    }
1✔
470

471
    boolean modifiedUser = false;
1✔
472

473
    if (institutionFromEmail != null) {
1✔
474
      if (handleUserWithInstitutionInMap(user, institutionFromEmail)) {
1✔
475
        modifiedUser = true;
1✔
476
      }
477
    } else {
478
      if (handleUserWithoutInstitutionInMap(user)) {
1✔
479
        modifiedUser = true;
1✔
480
      }
481
    }
482

483
    if (modifiedUser) {
1✔
484
      return findUserByEmail(user.getEmail());
1✔
485
    } else {
486
      return user;
×
487
    }
488
  }
489

490
  @VisibleForTesting
491
  protected boolean handleUserWithInstitutionInMap(User user, Institution institutionFromEmail) {
492
    boolean needsLCRemoved = needsLibraryCardRemovedForUser(user, institutionFromEmail);
1✔
493
    boolean needsInstitutionAssigned = !institutionFromEmail.getId()
1✔
494
        .equals(user.getInstitutionId());
1✔
495

496
    if (needsInstitutionAssigned && needsLCRemoved) {
1✔
497
      userServiceDAO.updateInstitutionAndClearLibraryCardForUser(user.getUserId(), institutionFromEmail.getId());
1✔
498
    } else if (needsInstitutionAssigned) {
1✔
499
      userDAO.updateInstitutionId(user.getUserId(), institutionFromEmail.getId());
1✔
500
    } else if (needsLCRemoved) {
1✔
501
      libraryCardDAO.deleteAllLibraryCardsByUser(user.getUserId());
1✔
502
    }
503

504
    return needsLCRemoved || needsInstitutionAssigned;
1✔
505
  }
506

507
  @VisibleForTesting
508
  protected boolean needsLibraryCardRemovedForUser(User user, Institution userInstitution) {
509
    boolean needsLCRemoved = false;
1✔
510
    if (hasLibraryCard(user)) {
1✔
511
      try {
512
        User lcIssuer = findUserById(user.getLibraryCard().getCreateUserId());
1✔
513
        Institution lcIssuerInstitution = institutionService.findInstitutionForEmail(lcIssuer.getEmail());
1✔
514
        if (!userInstitution.equals(lcIssuerInstitution)) {
1✔
515
          needsLCRemoved = true;
1✔
516
        }
517
      } catch (NotFoundException nfe) {
1✔
518
        needsLCRemoved = true;
1✔
519
      }
1✔
520
    }
521
    return needsLCRemoved;
1✔
522
  }
523

524
  @VisibleForTesting
525
  protected boolean handleUserWithoutInstitutionInMap(User user) {
526
    if (hasLibraryCard(user)) {
1✔
527
      dropLCAndInstitutionForUser(user);
1✔
528
      return true;
1✔
529
    } else {
530
      if (user.getInstitutionId() != null) {
1✔
531
        userDAO.updateInstitutionId(user.getUserId(), null);
1✔
532
        return true;
1✔
533
      }
534
    }
535
    return false;
×
536
  }
537

538
  private void dropLCAndInstitutionForUser(User user) {
539
    userServiceDAO.updateInstitutionAndClearLibraryCardForUser(user.getUserId(), null);
1✔
540
  }
1✔
541

542
  @VisibleForTesting
543
  protected boolean hasLibraryCard(User user) {
544
    return user.getLibraryCard() != null;
1✔
545
  }
546

547
  @VisibleForTesting
548
  protected boolean hasMatchingInstitutionInDatabase(
549
      Institution institutionFromEmail, Institution institutionFromDatabase) {
550
    if (institutionFromEmail == null || institutionFromDatabase == null) {
1✔
551
      return false;
1✔
552
    }
553
    return institutionFromDatabase.equals(institutionFromEmail);
1✔
554
  }
555

556
  public static class SimplifiedUser {
557

558
    private Integer userId;
559
    private String displayName;
560
    private String email;
561
    private Integer institutionId;
562

563
    public SimplifiedUser(User user) {
1✔
564
      this.userId = user.getUserId();
1✔
565
      this.displayName = user.getDisplayName();
1✔
566
      this.email = user.getEmail();
1✔
567
      this.institutionId = user.getInstitutionId();
1✔
568
    }
1✔
569

570
    public SimplifiedUser() {
1✔
571
    }
1✔
572

573
    public void setUserId(Integer userId) {
574
      this.userId = userId;
1✔
575
    }
1✔
576

577
    public void setDisplayName(String name) {
578
      this.displayName = name;
1✔
579
    }
1✔
580

581
    public void setEmail(String email) {
582
      this.email = email;
1✔
583
    }
1✔
584

585
    public void setInstitutionId(Integer institutionId) {
586
      this.institutionId = institutionId;
×
587
    }
×
588

589
    public String getDisplayName() {
590
      return displayName;
1✔
591
    }
592

593
    public String getEmail() {
594
      return email;
1✔
595
    }
596

597
    public Integer getInstitutionId() {
598
      return institutionId;
×
599
    }
600

601
    public Integer getUserId() {
602
      return userId;
1✔
603
    }
604

605
    @Override
606
    public boolean equals(Object o) {
607
      if (this == o) {
1✔
608
        return true;
×
609
      }
610
      if (o == null || getClass() != o.getClass()) {
1✔
611
        return false;
×
612
      }
613
      SimplifiedUser that = (SimplifiedUser) o;
1✔
614
      return Objects.equals(userId, that.userId);
1✔
615
    }
616

617
    @Override
618
    public int hashCode() {
619
      return Objects.hash(userId);
×
620
    }
621
  }
622
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc