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

DataBiosphere / consent / #6113

23 Jun 2025 12:49PM UTC coverage: 79.247% (-0.006%) from 79.253%
#6113

push

web-flow
[DT-1862] Use service method to populate needed information. (#2578)

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

10291 of 12986 relevant lines covered (79.25%)

0.79 hits per line

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

70.89
/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.HashSet;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Objects;
18
import java.util.Optional;
19
import java.util.Set;
20
import java.util.stream.Collectors;
21
import org.broadinstitute.consent.http.db.DacDAO;
22
import org.broadinstitute.consent.http.db.DataAccessRequestDAO;
23
import org.broadinstitute.consent.http.db.DatasetDAO;
24
import org.broadinstitute.consent.http.db.ElectionDAO;
25
import org.broadinstitute.consent.http.db.UserDAO;
26
import org.broadinstitute.consent.http.enumeration.ElectionType;
27
import org.broadinstitute.consent.http.enumeration.UserRoles;
28
import org.broadinstitute.consent.http.models.Dac;
29
import org.broadinstitute.consent.http.models.DataAccessAgreement;
30
import org.broadinstitute.consent.http.models.DataAccessRequest;
31
import org.broadinstitute.consent.http.models.Dataset;
32
import org.broadinstitute.consent.http.models.Election;
33
import org.broadinstitute.consent.http.models.Role;
34
import org.broadinstitute.consent.http.models.User;
35
import org.broadinstitute.consent.http.models.UserRole;
36
import org.broadinstitute.consent.http.service.dao.DacServiceDAO;
37
import org.broadinstitute.consent.http.util.ConsentLogger;
38

39
public class DacService implements ConsentLogger {
40

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

297
  public Set<Dac> findByDatasetId(List<Integer> datasetIds) {
NEW
298
    return dacDAO.findDacsForDatasetIds(datasetIds).stream().map(dac -> findById(dac.getDacId())).collect(
×
NEW
299
        Collectors.toUnmodifiableSet());
×
300
  }
301

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