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

DataBiosphere / consent / #5817

02 May 2025 01:06PM UTC coverage: 78.733% (-1.3%) from 80.036%
#5817

push

web-flow
DT-1595 Remove unused endpoints (#2507)

2 of 2 new or added lines in 1 file covered. (100.0%)

159 existing lines in 7 files now uncovered.

10029 of 12738 relevant lines covered (78.73%)

0.79 hits per line

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

71.79
/src/main/java/org/broadinstitute/consent/http/service/DacService.java
1
package org.broadinstitute.consent.http.service;
2

3
import static java.util.stream.Collectors.groupingBy;
4

5
import com.google.inject.Inject;
6
import jakarta.ws.rs.BadRequestException;
7
import jakarta.ws.rs.NotFoundException;
8
import java.sql.SQLException;
9
import java.util.ArrayList;
10
import java.util.Collections;
11
import java.util.Date;
12
import java.util.EnumSet;
13
import java.util.HashMap;
14
import java.util.List;
15
import java.util.Map;
16
import java.util.Objects;
17
import java.util.Optional;
18
import java.util.stream.Collectors;
19
import org.broadinstitute.consent.http.db.DacDAO;
20
import org.broadinstitute.consent.http.db.DataAccessRequestDAO;
21
import org.broadinstitute.consent.http.db.DatasetDAO;
22
import org.broadinstitute.consent.http.db.ElectionDAO;
23
import org.broadinstitute.consent.http.db.UserDAO;
24
import org.broadinstitute.consent.http.enumeration.ElectionType;
25
import org.broadinstitute.consent.http.enumeration.UserRoles;
26
import org.broadinstitute.consent.http.models.Dac;
27
import org.broadinstitute.consent.http.models.DataAccessAgreement;
28
import org.broadinstitute.consent.http.models.DataAccessRequest;
29
import org.broadinstitute.consent.http.models.Dataset;
30
import org.broadinstitute.consent.http.models.Election;
31
import org.broadinstitute.consent.http.models.Role;
32
import org.broadinstitute.consent.http.models.User;
33
import org.broadinstitute.consent.http.models.UserRole;
34
import org.broadinstitute.consent.http.service.dao.DacServiceDAO;
35
import org.broadinstitute.consent.http.util.ConsentLogger;
36

37
public class DacService implements ConsentLogger {
38

39
  private final DacDAO dacDAO;
40
  private final UserDAO userDAO;
41
  private final DatasetDAO dataSetDAO;
42
  private final ElectionDAO electionDAO;
43
  private final DataAccessRequestDAO dataAccessRequestDAO;
44
  private final VoteService voteService;
45
  private final DaaService daaService;
46
  private final DacServiceDAO dacServiceDAO;
47

48
  @Inject
49
  public DacService(DacDAO dacDAO, UserDAO userDAO, DatasetDAO dataSetDAO,
50
      ElectionDAO electionDAO, DataAccessRequestDAO dataAccessRequestDAO,
51
      VoteService voteService, DaaService daaService,
52
      DacServiceDAO dacServiceDAO) {
1✔
53
    this.dacDAO = dacDAO;
1✔
54
    this.userDAO = userDAO;
1✔
55
    this.dataSetDAO = dataSetDAO;
1✔
56
    this.electionDAO = electionDAO;
1✔
57
    this.dataAccessRequestDAO = dataAccessRequestDAO;
1✔
58
    this.voteService = voteService;
1✔
59
    this.daaService = daaService;
1✔
60
    this.dacServiceDAO = dacServiceDAO;
1✔
61
  }
1✔
62

63
  public List<Dac> findAll() {
64
    List<Dac> dacs = dacDAO.findAll();
1✔
65
    for (Dac dac : dacs) {
1✔
66
      DataAccessAgreement associatedDaa = dac.getAssociatedDaa();
1✔
67
      associatedDaa.setBroadDaa(daaService.isBroadDAA(associatedDaa.getDaaId(), List.of(associatedDaa), List.of(dac)));
1✔
68
      dac.setAssociatedDaa(associatedDaa);
1✔
69
    }
1✔
70
    return dacs;
1✔
71
  }
72

73
  public List<User> findAllDACUsersBySearchString(String term) {
74
    return dacDAO.findAllDACUsersBySearchString(term).stream().distinct()
×
75
        .collect(Collectors.toList());
×
76
  }
77

78
  private List<Dac> addMemberInfoToDacs(List<Dac> dacs) {
UNCOV
79
    List<User> allDacMembers = dacDAO.findAllDACUserMemberships().stream().distinct()
×
UNCOV
80
        .collect(Collectors.toList());
×
UNCOV
81
    Map<Dac, List<User>> dacToUserMap = groupUsersByDacs(dacs, allDacMembers);
×
UNCOV
82
    return dacs.stream().peek(d -> {
×
UNCOV
83
      List<User> chairs = dacToUserMap.get(d).stream().
×
UNCOV
84
          filter(u -> u.getRoles().stream().
×
UNCOV
85
              anyMatch(
×
UNCOV
86
                  ur -> ur.getRoleId().equals(UserRoles.CHAIRPERSON.getRoleId()) && ur.getDacId()
×
UNCOV
87
                      .equals(d.getDacId()))).
×
UNCOV
88
          collect(Collectors.toList());
×
UNCOV
89
      List<User> members = dacToUserMap.get(d).stream().
×
UNCOV
90
          filter(u -> u.getRoles().stream().
×
UNCOV
91
              anyMatch(ur -> ur.getRoleId().equals(UserRoles.MEMBER.getRoleId()) && ur.getDacId()
×
UNCOV
92
                  .equals(d.getDacId()))).
×
UNCOV
93
          collect(Collectors.toList());
×
UNCOV
94
      d.setChairpersons(chairs);
×
UNCOV
95
      d.setMembers(members);
×
UNCOV
96
    }).collect(Collectors.toList());
×
97
  }
98

99
  /**
100
   * Convenience method to group DACUsers into their associated Dacs. Users can be in more than a
101
   * single Dac, and a Dac can have multiple types of users, either Chairpersons or Members.
102
   *
103
   * @param dacs          List of all Dacs
104
   * @param allDacMembers List of all DACUsers, i.e. users that are in any Dac.
105
   * @return Map of Dac to list of DACUser
106
   */
107
  private Map<Dac, List<User>> groupUsersByDacs(List<Dac> dacs, List<User> allDacMembers) {
UNCOV
108
    Map<Integer, Dac> dacMap = dacs.stream().collect(Collectors.toMap(Dac::getDacId, d -> d));
×
UNCOV
109
    Map<Integer, User> userMap = allDacMembers.stream()
×
UNCOV
110
        .collect(Collectors.toMap(User::getUserId, u -> u));
×
UNCOV
111
    Map<Dac, List<User>> dacToUserMap = new HashMap<>();
×
UNCOV
112
    dacs.forEach(d -> dacToUserMap.put(d, new ArrayList<>()));
×
UNCOV
113
    allDacMembers.stream().
×
UNCOV
114
        flatMap(u -> u.getRoles().stream()).
×
UNCOV
115
        filter(ur -> ur.getRoleId().equals(UserRoles.CHAIRPERSON.getRoleId()) ||
×
UNCOV
116
            ur.getRoleId().equals(UserRoles.MEMBER.getRoleId())).
×
UNCOV
117
        forEach(ur -> {
×
UNCOV
118
          Dac d = dacMap.get(ur.getDacId());
×
UNCOV
119
          User u = userMap.get(ur.getUserId());
×
UNCOV
120
          if (d != null && u != null && dacToUserMap.containsKey(d)) {
×
UNCOV
121
            dacToUserMap.get(d).add(u);
×
122
          }
UNCOV
123
        });
×
UNCOV
124
    return dacToUserMap;
×
125
  }
126

127
  public List<Dac> findDacsWithMembersOption(Boolean withMembers) {
128
    List<Dac> dacs = dacDAO.findAll();
1✔
129
    if (withMembers) {
1✔
130
      return addMemberInfoToDacs(dacs);
×
131
    }
132
    return dacs;
1✔
133
  }
134

135
  public Dac findById(Integer dacId) {
136
    Dac dac = dacDAO.findById(dacId);
1✔
137
    List<User> chairs = dacDAO.findMembersByDacIdAndRoleId(dacId,
1✔
138
        UserRoles.CHAIRPERSON.getRoleId());
1✔
139
    List<User> members = dacDAO.findMembersByDacIdAndRoleId(dacId, UserRoles.MEMBER.getRoleId());
1✔
140
    if (Objects.nonNull(dac)) {
1✔
141
      dac.setChairpersons(chairs);
1✔
142
      dac.setMembers(members);
1✔
143
      if (dac.getAssociatedDaa() != null) {
1✔
144
        DataAccessAgreement associatedDaa = dac.getAssociatedDaa();
1✔
145
        associatedDaa.setBroadDaa(daaService.isBroadDAA(associatedDaa.getDaaId(), List.of(associatedDaa), List.of(dac)));
1✔
146
        dac.setAssociatedDaa(associatedDaa);
1✔
147
      }
148
      return dac;
1✔
149
    }
150
    throw new NotFoundException("Could not find DAC with the provided id: " + dacId);
×
151
  }
152

153
  public Integer createDac(String name, String description) {
154
    Date createDate = new Date();
1✔
155
    return dacDAO.createDac(name, description, createDate);
1✔
156
  }
157

158
  public Integer createDac(String name, String description, String email) {
159
    Date createDate = new Date();
1✔
160
    return dacDAO.createDac(name, description, email, createDate);
1✔
161
  }
162

163
  public void updateDac(String name, String description, Integer dacId) {
164
    Date updateDate = new Date();
1✔
165
    dacDAO.updateDac(name, description, updateDate, dacId);
1✔
166
  }
1✔
167

168
  public void updateDac(String name, String description, String email, Integer dacId) {
169
    Date updateDate = new Date();
1✔
170
    dacDAO.updateDac(name, description, email, updateDate, dacId);
1✔
171
  }
1✔
172

173
  public void deleteDac(Integer dacId) throws IllegalArgumentException, SQLException {
174
    Dac fullDac = dacDAO.findById(dacId);
1✔
175
    // TODO: Broad DAC logic will be updated with DCJ-498 to not be reliant on name
176
    if (fullDac.getName().toLowerCase().contains("broad")) {
1✔
177
      throw new IllegalArgumentException("This is the Broad DAC, which can not be deleted.");
1✔
178
    }
179
    try {
180
      dacServiceDAO.deleteDacAndDaas(fullDac);
1✔
181
    } catch (IllegalArgumentException e) {
1✔
182
      String logMessage = "Could not find DAC with the provided id: " + dacId;
1✔
183
      logException(logMessage, e);
1✔
184
      throw new IllegalArgumentException(logMessage);
1✔
185
    }
1✔
186
  }
1✔
187

188
  public User findUserById(Integer id) throws IllegalArgumentException {
189
    return userDAO.findUserById(id);
×
190
  }
191

192
  public List<Dataset> findDatasetsByDacId(Integer dacId) {
193
    return dataSetDAO.findDatasetsAssociatedWithDac(dacId);
1✔
194
  }
195

196
  public List<User> findMembersByDacId(Integer dacId) {
197
    List<User> users = dacDAO.findMembersByDacId(dacId);
1✔
198
    List<Integer> allUserIds = users.
1✔
199
        stream().
1✔
200
        map(User::getUserId).
1✔
201
        distinct().
1✔
202
        collect(Collectors.toList());
1✔
203
    Map<Integer, List<UserRole>> userRoleMap = new HashMap<>();
1✔
204
    if (!allUserIds.isEmpty()) {
1✔
205
      userRoleMap.putAll(dacDAO.findUserRolesForUsers(allUserIds).
1✔
206
          stream().
1✔
207
          collect(groupingBy(UserRole::getUserId)));
1✔
208
    }
209
    users.forEach(u -> {
1✔
210
      if (userRoleMap.containsKey(u.getUserId())) {
1✔
211
        u.setRoles(userRoleMap.get(u.getUserId()));
1✔
212
      }
213
    });
1✔
214
    return users;
1✔
215
  }
216

217
  public User addDacMember(Role role, User user, Dac dac) throws IllegalArgumentException {
218
    dacDAO.addDacMember(role.getRoleId(), user.getUserId(), dac.getDacId());
1✔
219
    User updatedUser = userDAO.findUserById(user.getUserId());
1✔
220
    List<Election> elections = electionDAO.findOpenElectionsByDacId(dac.getDacId());
1✔
221
    for (Election e : elections) {
1✔
222
      IllegalArgumentException noTypeException = new IllegalArgumentException(
1✔
223
          "Unable to determine election type for election id: " + e.getElectionId());
1✔
224
      if (Objects.isNull(e.getElectionType())) {
1✔
225
        throw noTypeException;
×
226
      }
227
      Optional<ElectionType> type = EnumSet.allOf(ElectionType.class).stream().
1✔
228
          filter(t -> t.getValue().equalsIgnoreCase(e.getElectionType())).findFirst();
1✔
229
      if (!type.isPresent()) {
1✔
230
        throw noTypeException;
×
231
      }
232
      boolean isManualReview =
1✔
233
          type.get().equals(ElectionType.DATA_ACCESS) && hasUseRestriction(e.getReferenceId());
1✔
234
      voteService.createVotesForUser(updatedUser, e, type.get(), isManualReview);
1✔
235
    }
1✔
236
    return userDAO.findUserById(updatedUser.getUserId());
1✔
237
  }
238

239
  public void removeDacMember(Role role, User user, Dac dac) throws BadRequestException {
240
    if (role.getRoleId().equals(UserRoles.CHAIRPERSON.getRoleId())) {
1✔
241
      if (dac.getChairpersons().size() <= 1) {
1✔
242
        throw new BadRequestException("Dac requires at least one chairperson.");
1✔
243
      }
244
    }
245
    List<UserRole> dacRoles = user.
1✔
246
        getRoles().
1✔
247
        stream().
1✔
248
        filter(r -> Objects.nonNull(r.getDacId())).
1✔
249
        filter(r -> r.getDacId().equals(dac.getDacId())).
1✔
250
        filter(r -> r.getRoleId().equals(role.getRoleId())).
1✔
251
        collect(Collectors.toList());
1✔
252
    dacRoles.forEach(userRole -> dacDAO.removeDacMember(userRole.getUserRoleId()));
1✔
253
    voteService.deleteOpenDacVotesForUser(dac, user);
1✔
254
  }
1✔
255

256
  public Role getChairpersonRole() {
257
    return dacDAO.getRoleById(UserRoles.CHAIRPERSON.getRoleId());
×
258
  }
259

260
  public Role getMemberRole() {
261
    return dacDAO.getRoleById(UserRoles.MEMBER.getRoleId());
×
262
  }
263

264
  private boolean hasUseRestriction(String referenceId) {
265
    DataAccessRequest dar = dataAccessRequestDAO.findByReferenceId(referenceId);
1✔
266
    return Objects.nonNull(dar) &&
1✔
267
        Objects.nonNull(dar.getData()) &&
1✔
268
        Objects.nonNull(dar.getData().getRestriction());
1✔
269
  }
270

271
  /**
272
   * Filter data access requests by the DAC they are associated with.
273
   */
274
  List<DataAccessRequest> filterDataAccessRequestsByDac(List<DataAccessRequest> documents,
275
      User user) {
276
    if (Objects.nonNull(user)) {
1✔
277
      if (user.hasUserRole(UserRoles.ADMIN)) {
1✔
278
        return documents;
1✔
279
      }
280
      // Chair and Member users can see data access requests that they have DAC access to
281
      if (user.hasUserRole(UserRoles.MEMBER) || user.hasUserRole(UserRoles.CHAIRPERSON)) {
1✔
282
        List<Integer> accessibleDatasetIds = dataSetDAO.findDatasetIdsByDACUserId(user.getUserId());
1✔
283
        return documents.
1✔
284
            stream().
1✔
285
            filter(d -> {
1✔
286
              List<Integer> datasetIds = d.getDatasetIds();
1✔
287
              return accessibleDatasetIds.stream().anyMatch(datasetIds::contains);
1✔
288
            }).
289
            collect(Collectors.toList());
1✔
290
      }
291
    }
292
    return Collections.emptyList();
×
293
  }
294

295
}
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