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

DataBiosphere / consent / #5715

23 Apr 2025 02:30PM UTC coverage: 78.981% (+0.03%) from 78.956%
#5715

push

web-flow
DT-1546: Verify that user's email matches institution during library card creation (#2493)

23 of 26 new or added lines in 2 files covered. (88.46%)

1 existing line in 1 file now uncovered.

10217 of 12936 relevant lines covered (78.98%)

0.79 hits per line

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

89.93
/src/main/java/org/broadinstitute/consent/http/service/LibraryCardService.java
1
package org.broadinstitute.consent.http.service;
2

3
import com.google.inject.Inject;
4
import jakarta.ws.rs.BadRequestException;
5
import jakarta.ws.rs.NotFoundException;
6
import java.util.ArrayList;
7
import java.util.Date;
8
import java.util.List;
9
import java.util.Objects;
10
import java.util.Optional;
11
import org.broadinstitute.consent.http.db.InstitutionDAO;
12
import org.broadinstitute.consent.http.db.LibraryCardDAO;
13
import org.broadinstitute.consent.http.db.UserDAO;
14
import org.broadinstitute.consent.http.enumeration.UserRoles;
15
import org.broadinstitute.consent.http.exceptions.ConsentConflictException;
16
import org.broadinstitute.consent.http.models.Institution;
17
import org.broadinstitute.consent.http.models.LibraryCard;
18
import org.broadinstitute.consent.http.models.User;
19

20
public class LibraryCardService {
21

22
  private final LibraryCardDAO libraryCardDAO;
23
  private final InstitutionDAO institutionDAO;
24
  private final InstitutionService institutionService;
25
  private final UserDAO userDAO;
26

27
  @Inject
28
  public LibraryCardService(LibraryCardDAO libraryCardDAO, InstitutionDAO institutionDAO,
29
      InstitutionService institutionService,
30
      UserDAO userDAO) {
1✔
31
    this.libraryCardDAO = libraryCardDAO;
1✔
32
    this.institutionDAO = institutionDAO;
1✔
33
    this.institutionService = institutionService;
1✔
34
    this.userDAO = userDAO;
1✔
35
  }
1✔
36

37
  public LibraryCard createLibraryCard(LibraryCard libraryCard, User user) {
38
    throwIfNull(libraryCard);
1✔
39
    boolean isAdmin = checkIsAdmin(user);
1✔
40
    //If user is not an admin, use user's institutionId rather than the value provided in the payload
41
    if (!isAdmin && !libraryCard.getInstitutionId().equals(user.getInstitutionId())) {
1✔
42
      throw new BadRequestException("Card payload not valid");
1✔
43
    }
44
    checkIfCardExists(libraryCard);
1✔
45
    processUserOnNewLC(libraryCard);
1✔
46
    checkForValidInstitution(libraryCard.getInstitutionId(), libraryCard.getUserEmail());
1✔
47
    Date createDate = new Date();
1✔
48
    Integer id = libraryCardDAO.insertLibraryCard(
1✔
49
        libraryCard.getUserId(),
1✔
50
        libraryCard.getInstitutionId(),
1✔
51
        libraryCard.getEraCommonsId(),
1✔
52
        libraryCard.getUserName(),
1✔
53
        libraryCard.getUserEmail(),
1✔
54
        libraryCard.getCreateUserId(),
1✔
55
        createDate);
56
    return libraryCardDAO.findLibraryCardById(id);
1✔
57
  }
58

59
  public LibraryCard updateLibraryCard(LibraryCard libraryCard, Integer id, Integer userId) {
60
    LibraryCard updateCard = libraryCardDAO.findLibraryCardById(id);
1✔
61
    throwIfNull(updateCard);
1✔
62
    checkUserId(userId);
1✔
63
    checkForValidUser(libraryCard.getUserId());
1✔
64
    checkForValidInstitution(libraryCard.getInstitutionId(), libraryCard.getUserEmail());
1✔
65

66
    Date updateDate = new Date();
1✔
67
    libraryCardDAO.updateLibraryCardById(
1✔
68
        id,
69
        libraryCard.getUserId(),
1✔
70
        libraryCard.getInstitutionId(),
1✔
71
        libraryCard.getEraCommonsId(),
1✔
72
        libraryCard.getUserName(),
1✔
73
        libraryCard.getUserEmail(),
1✔
74
        userId,
75
        updateDate
76
    );
77
    return libraryCardDAO.findLibraryCardById(id);
1✔
78
  }
79

80
  public void deleteLibraryCardById(Integer id) {
81
    LibraryCard card = findLibraryCardById(id);
×
82
    throwIfNull(card);
×
83
    libraryCardDAO.deleteLibraryCardById(id);
×
84
  }
×
85

86
  public List<LibraryCard> findAllLibraryCards() {
87
    return libraryCardDAO.findAllLibraryCards();
×
88
  }
89

90
  public List<LibraryCard> findLibraryCardsByUserId(Integer userId) {
91
    return libraryCardDAO.findLibraryCardsByUserId(userId);
1✔
92
  }
93

94
  public List<LibraryCard> findLibraryCardsByInstitutionId(Integer institutionId) {
95
    return libraryCardDAO.findLibraryCardsByInstitutionId(institutionId);
×
96
  }
97

98
  public LibraryCard findLibraryCardById(Integer libraryCardId) {
99
    LibraryCard libraryCard = libraryCardDAO.findLibraryCardById(libraryCardId);
1✔
100
    throwIfNull(libraryCard);
1✔
101
    return libraryCard;
1✔
102
  }
103

104
  public LibraryCard findLibraryCardWithDaasById(Integer libraryCardId) {
105
    LibraryCard libraryCard = libraryCardDAO.findLibraryCardDaaById(libraryCardId);
1✔
106
    throwIfNull(libraryCard);
1✔
107
    return libraryCard;
1✔
108
  }
109

110
  public void addDaaToLibraryCard(Integer libraryCardId, Integer daaId) {
111
    libraryCardDAO.createLibraryCardDaaRelation(libraryCardId, daaId);
1✔
112
  }
1✔
113

114
  public void removeDaaFromLibraryCard(Integer libraryCardId, Integer daaId) {
115
    libraryCardDAO.deleteLibraryCardDaaRelation(libraryCardId, daaId);
1✔
116
  }
1✔
117

118
  public List<LibraryCard> addDaaToUserLibraryCardByInstitution(User user, User signingOfficial, Integer daaId) {
119
    if (signingOfficial.getInstitutionId() == null) {
1✔
120
      throw new BadRequestException("This signing official does not have an institution.");
1✔
121
    }
122
    List<LibraryCard> libraryCards = new ArrayList<>(libraryCardDAO.findLibraryCardsByUserIdInstitutionId(user.getUserId(), signingOfficial.getInstitutionId()));
1✔
123
    if (libraryCards.isEmpty()) {
1✔
124
      LibraryCard lc = createLibraryCardForSigningOfficial(user, signingOfficial);
1✔
125
      libraryCards.add(lc);
1✔
126
    }
127
    // typically there should be one library card per user per institution
128
    for (LibraryCard libraryCard : libraryCards) {
1✔
129
      addDaaToLibraryCard(libraryCard.getId(), daaId);
1✔
130
    }
1✔
131
    return libraryCardDAO.findLibraryCardsByUserIdInstitutionId(user.getUserId(), signingOfficial.getInstitutionId());
1✔
132
  }
133

134
  public List<LibraryCard> removeDaaFromUserLibraryCardByInstitution(User user, Integer institutionId, Integer daaId) {
135
    List<LibraryCard> libraryCards = findLibraryCardsByUserId(user.getUserId());
1✔
136
    List<LibraryCard> matchingLibraryCards = libraryCards.stream()
1✔
137
        .filter(card -> Objects.equals(card.getInstitutionId(), institutionId))
1✔
138
        .toList();
1✔
139
    // typically there should be one library card per user per institution
140
    for (LibraryCard libraryCard : matchingLibraryCards) {
1✔
141
      removeDaaFromLibraryCard(libraryCard.getId(), daaId);
1✔
142
    }
1✔
143
    return matchingLibraryCards;
1✔
144
  }
145

146
  public LibraryCard createLibraryCardForSigningOfficial(User user, User signingOfficial) {
147
    LibraryCard lc = new LibraryCard();
1✔
148
    lc.setUserId(user.getUserId());
1✔
149
    lc.setInstitutionId(signingOfficial.getInstitutionId());
1✔
150
    lc.setEraCommonsId(user.getEraCommonsId());
1✔
151
    lc.setUserName(user.getDisplayName());
1✔
152
    lc.setUserEmail(user.getEmail());
1✔
153
    lc.setCreateUserId(signingOfficial.getUserId());
1✔
154
    LibraryCard createdLc = createLibraryCard(lc, user);
1✔
155
    return createdLc;
1✔
156
  }
157

158
  private void checkForValidInstitution(Integer institutionId, String userEmail) {
159
    checkInstitutionId(institutionId);
1✔
160
    Institution institution = institutionDAO.findInstitutionById(institutionId);
1✔
161

162
    if (Objects.isNull(institution)) {
1✔
163
      throw new IllegalArgumentException("Invalid Institution Id");
1✔
164
    }
165

166
    var userInstitution = institutionService.findInstitutionForEmail(userEmail);
1✔
167
    if (userInstitution == null || !userInstitution.getId().equals(institutionId)) {
1✔
NEW
168
      throw new BadRequestException(
×
NEW
169
          "User email %s does not match institution %s".formatted(userEmail, institution.getName()));
×
170
    }
171
  }
1✔
172

173
  private void checkForValidUser(Integer userId) {
174
    if (Objects.isNull(userId)) {
1✔
175
      return;
×
176
    }
177

178
    User user = userDAO.findUserById(userId);
1✔
179
    if (Objects.isNull(user)) {
1✔
180
      throw new IllegalArgumentException("Invalid User Id");
×
181
    }
182
  }
1✔
183

184
  private void checkInstitutionId(Integer institutionId) {
185
    if (Objects.isNull(institutionId)) {
1✔
186
      throw new IllegalArgumentException("Institution ID is a required parameter");
×
187
    }
188
  }
1✔
189

190
  private void checkUserId(Integer userId) {
191
    if (Objects.isNull(userId)) {
1✔
192
      throw new IllegalArgumentException("User ID is a required parameter");
×
193
    }
194
  }
1✔
195

196
  private void throwIfNull(LibraryCard libraryCard) {
197
    if (Objects.isNull(libraryCard)) {
1✔
198
      throw new NotFoundException("LibraryCard not found.");
1✔
199
    }
200
  }
1✔
201

202
  //helper method for create method, checks to see if card already exists
203
  private void checkIfCardExists(LibraryCard payload) {
204
    Integer userId = payload.getUserId();
1✔
205
    String email = payload.getUserEmail();
1✔
206
    Integer institutionId = payload.getInstitutionId();
1✔
207
    Optional<LibraryCard> foundCard;
208
    List<LibraryCard> results;
209

210
    if (Objects.nonNull(payload.getUserId())) {
1✔
211
      results = libraryCardDAO.findLibraryCardsByUserId(userId);
1✔
212
    } else if (Objects.nonNull(email)) {
1✔
213
      results = libraryCardDAO.findAllLibraryCardsByUserEmail(email);
1✔
214
    } else {
215
      throw new BadRequestException();
1✔
216
    }
217
    foundCard = results.stream().filter(card -> {
1✔
218
      Boolean sameUserId = Objects.nonNull(userId) && card.getUserId().equals(userId);
1✔
219
      Boolean sameUserEmail = Objects.nonNull(email) && card.getUserEmail().equalsIgnoreCase(email);
1✔
220
      Boolean sameInstitution = card.getInstitutionId().equals(institutionId);
1✔
221
      return (sameUserId || sameUserEmail) && sameInstitution;
1✔
222
    }).findFirst();
1✔
223

224
    if (foundCard.isPresent()) {
1✔
225
      throw new ConsentConflictException();
1✔
226
    }
227
  }
1✔
228

229
  // Helper method to process user data on create LC payload.
230
  // Needed since CREATE has a unique situation where admins can create LCs without an active
231
  // user (save with userEmail instead).
232
  private void processUserOnNewLC(LibraryCard card) {
233
    if (card.getUserId() == null) {
1✔
234
      // No user ID is provided, email must exist in card request.
235
      if (card.getUserEmail() == null) {
1✔
UNCOV
236
        throw new BadRequestException();
×
237
      }
238
      // If a user is found, update the card to have the correct userId associated.
239
      User user = userDAO.findUserByEmail(card.getUserEmail());
1✔
240
      if (user != null) {
1✔
NEW
241
        card.setUserId(user.getUserId());
×
242
      }
243
    } else {
1✔
244
      // check if userId exists
245
      User user = userDAO.findUserById(card.getUserId());
1✔
246
      if (user == null) {
1✔
247
        throw new BadRequestException();
1✔
248
      }
249
      if (card.getUserEmail() == null) {
1✔
250
        // if no email is provided in the card request, use the one from the user.
251
        card.setUserEmail(user.getEmail());
1✔
252
      } else if (!(user.getEmail().equalsIgnoreCase(card.getUserEmail()))) {
1✔
253
        // Emails do not match, throw an error.
254
        throw new ConsentConflictException();
1✔
255
      }
256
      card.setUserName(user.getDisplayName());
1✔
257
    }
258
  }
1✔
259

260
  private boolean checkIsAdmin(User user) {
261
    return user.getRoles()
1✔
262
        .stream()
1✔
263
        .anyMatch(role -> role.getName().equalsIgnoreCase(UserRoles.ADMIN.getRoleName()));
1✔
264
  }
265
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc