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

DataBiosphere / consent / #5188

10 Jul 2024 02:12PM UTC coverage: 77.026% (+0.08%) from 76.943%
#5188

push

web-flow
[DCJ-481] Add "Broad DAA" flag to appropriate DAA (#2351)

46 of 46 new or added lines in 4 files covered. (100.0%)

2 existing lines in 2 files now uncovered.

9988 of 12967 relevant lines covered (77.03%)

0.77 hits per line

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

96.67
/src/main/java/org/broadinstitute/consent/http/service/DaaService.java
1
package org.broadinstitute.consent.http.service;
2

3
import com.google.cloud.storage.BlobId;
4
import com.google.gson.Gson;
5
import com.google.gson.JsonElement;
6
import com.google.gson.JsonObject;
7
import com.google.inject.Inject;
8
import jakarta.ws.rs.BadRequestException;
9
import jakarta.ws.rs.NotFoundException;
10
import jakarta.ws.rs.ServerErrorException;
11
import jakarta.ws.rs.core.MediaType;
12
import java.io.IOException;
13
import java.io.InputStream;
14
import java.util.Comparator;
15
import java.util.List;
16
import java.util.Optional;
17
import java.util.UUID;
18
import java.util.stream.Collectors;
19
import org.apache.commons.lang3.StringUtils;
20
import org.broadinstitute.consent.http.cloudstore.GCSService;
21
import org.broadinstitute.consent.http.db.DaaDAO;
22
import org.broadinstitute.consent.http.db.DacDAO;
23
import org.broadinstitute.consent.http.db.InstitutionDAO;
24
import org.broadinstitute.consent.http.enumeration.FileCategory;
25
import org.broadinstitute.consent.http.models.Dac;
26
import org.broadinstitute.consent.http.models.DataAccessAgreement;
27
import org.broadinstitute.consent.http.models.FileStorageObject;
28
import org.broadinstitute.consent.http.models.Institution;
29
import org.broadinstitute.consent.http.models.User;
30
import org.broadinstitute.consent.http.service.UserService.SimplifiedUser;
31
import org.broadinstitute.consent.http.service.dao.DaaServiceDAO;
32
import org.broadinstitute.consent.http.util.ConsentLogger;
33
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
34

35
public class DaaService implements ConsentLogger {
36

37
  private final DaaServiceDAO daaServiceDAO;
38
  private final DaaDAO daaDAO;
39
  private final GCSService gcsService;
40
  private final EmailService emailService;
41
  private final UserService userService;
42
  private final InstitutionDAO institutionDAO;
43
  private final DacDAO dacDAO;
44

45
  @Inject
46
  public DaaService(DaaServiceDAO daaServiceDAO, DaaDAO daaDAO, GCSService gcsService, EmailService emailService, UserService userService, InstitutionDAO institutionDAO, DacDAO dacDAO) {
1✔
47
    this.daaServiceDAO = daaServiceDAO;
1✔
48
    this.daaDAO = daaDAO;
1✔
49
    this.gcsService = gcsService;
1✔
50
    this.emailService = emailService;
1✔
51
    this.userService = userService;
1✔
52
    this.institutionDAO = institutionDAO;
1✔
53
    this.dacDAO = dacDAO;
1✔
54
  }
1✔
55

56
  /**
57
   * Create a new DataAccessAgreement with file content.
58
   *
59
   * @param userId The create User ID
60
   * @param dacId The initial DAC ID
61
   * @param inputStream The file content
62
   * @param fileDetail The file details
63
   * @return The created DataAccessAgreement
64
   * @throws ServerErrorException The Exception
65
   */
66
  public DataAccessAgreement createDaaWithFso(Integer userId, Integer dacId,
67
      InputStream inputStream,
68
      FormDataContentDisposition fileDetail)
69
      throws ServerErrorException {
70
    UUID id = UUID.randomUUID();
1✔
71
    BlobId blobId;
72
    try {
73
      blobId = gcsService.storeDocument(inputStream, fileDetail.getType(), id);
1✔
74
    } catch (IOException e) {
1✔
75
      logException(String.format("Error storing DAA file in GCS. User ID: %s; Dac ID: %s. ", userId, dacId), e);
1✔
76
      throw new ServerErrorException("Error storing DAA file in GCS.", 500);
1✔
77
    }
1✔
78
    Integer daaId;
79
    try {
80
      String mediaType = switch (StringUtils.substringAfterLast(fileDetail.getFileName(), ".")) {
1✔
81
        case "png", "gif", "jpg", "jpeg" -> "image";
×
82
        default -> MediaType.APPLICATION_OCTET_STREAM;
1✔
83
      };
84
      FileStorageObject fso = new FileStorageObject();
1✔
85
      fso.setBlobId(blobId);
1✔
86
      fso.setFileName(fileDetail.getFileName());
1✔
87
      fso.setCategory(FileCategory.DATA_ACCESS_AGREEMENT);
1✔
88
      fso.setMediaType(mediaType);
1✔
89
      daaId = daaServiceDAO.createDaaWithFso(userId, dacId, fso);
1✔
90
    } catch (Exception e) {
1✔
91
      try {
92
        gcsService.deleteDocument(blobId.getName());
×
93
      } catch (Exception ex) {
1✔
94
        logException(String.format("Error deleting DAA file from GCS. User ID: %s; Dac ID: %s. ", userId, dacId), ex);
1✔
95
      }
×
96
      logException(String.format("Error saving DAA. User ID: %s; Dac ID: %s. ", userId, dacId), e);
1✔
97
      throw new ServerErrorException("Error saving DAA.", 500);
1✔
98
    }
1✔
99
    return daaDAO.findById(daaId);
1✔
100
  }
101

102
  public void addDacToDaa(Integer dacId, Integer daaId) {
103
    daaDAO.createDacDaaRelation(dacId, daaId);
1✔
104
  }
1✔
105

106
  public void removeDacFromDaa(Integer dacId, Integer daaId) {
107
    daaDAO.deleteDacDaaRelation(dacId, daaId);
1✔
108
  }
1✔
109

110
  // Note: This method/implementation is not the permanent solution to identifying the Broad DAA.
111
  // Work is ticketed to refactor this logic.
112
  public boolean isBroadDAA(int daaId, List<DataAccessAgreement> allDaas, List<Dac> allDacs) {
113
    // Artificially tag the Broad/DUOS DAA as a reference DAA.
114
    Optional<Dac> broadDac = allDacs.stream()
1✔
115
        .filter(dac -> dac.getName().toLowerCase().contains("broad")).findFirst();
1✔
116
    if (broadDac.isPresent()) {
1✔
117
      Optional<DataAccessAgreement> broadDAA = allDaas.stream()
1✔
118
          .filter(daa -> daa.getInitialDacId().equals(broadDac.get().getDacId())).findFirst();
1✔
119
      broadDAA.ifPresent(daa -> daa.setBroadDaa(true));
1✔
120
    } else {
1✔
121
      // In this case, we want the first created DAA to be the Broad default DAA.
122
      allDaas.stream().min(Comparator.comparing(DataAccessAgreement::getDaaId))
1✔
123
          .ifPresent(daa -> daa.setBroadDaa(true));
1✔
124
    }
125
    Optional<DataAccessAgreement> broadDaa = allDaas.stream().filter(daa -> daa.getDaaId().equals(daaId)).findFirst();
1✔
126
    if (broadDaa.isPresent()) {
1✔
127
      return broadDaa.get().getBroadDaa();
1✔
128
    } else {
129
      return false;
1✔
130
    }
131
  }
132

133
  public List<DataAccessAgreement> findAll() {
134
      List<DataAccessAgreement> daas = daaDAO.findAll();
1✔
135
      List<Dac> allDacs = dacDAO.findAll();
1✔
136
      if (daas != null) {
1✔
137
        daas.forEach(daa -> {
1✔
138
          daa.setBroadDaa(
1✔
139
              isBroadDAA(daa.getDaaId(), daas, allDacs)
1✔
140
          );
141
        });
1✔
142
        return daas;
1✔
143
      }
UNCOV
144
    return List.of();
×
145
  }
146

147
  public DataAccessAgreement findById(Integer daaId) {
148
    DataAccessAgreement daa = daaDAO.findById(daaId);
1✔
149
    if (daa != null) {
1✔
150
      return daa;
1✔
151
    }
152
    throw new NotFoundException("Could not find DAA with the provided ID: " + daaId);
1✔
153
  }
154

155
  public void sendDaaRequestEmails(User user, Integer daaId) throws Exception {
156
    try {
157
      Institution institution = institutionDAO.findInstitutionWithSOById(user.getInstitutionId());
1✔
158
      if (institution == null) {
1✔
159
        throw new BadRequestException("This user has not set their institution: " + user.getDisplayName());
1✔
160
      }
161
      List<SimplifiedUser> signingOfficials = institution.getSigningOfficials();
1✔
162
      if (signingOfficials.isEmpty()) {
1✔
163
        throw new NotFoundException("No signing officials found for user: " + user.getDisplayName());
1✔
164
      }
165
      int userId = user.getUserId();
1✔
166
      String userName = user.getDisplayName();
1✔
167
      for (SimplifiedUser signingOfficial : signingOfficials) {
1✔
168
        DataAccessAgreement daa = findById(daaId);
1✔
169
        String daaName = daa.getFile().getFileName();
1✔
170
        emailService.sendDaaRequestMessage( signingOfficial.displayName, signingOfficial.email,
1✔
171
            userName, daaName, daaId, userId);
1✔
172
      }
1✔
173
    } catch (Exception e) {
1✔
174
      logException(e);
1✔
175
      throw(e);
1✔
176
    }
1✔
177
  }
1✔
178

179
  public void sendNewDaaEmails(User user, Integer daaId, String dacName, String newDaaName) throws Exception {
180
    try {
181
      DataAccessAgreement daa = findById(daaId);
1✔
182
      if (daa != null) {
1✔
183
        String previousDaaName = daa.getFile().getFileName();
1✔
184
        List<SimplifiedUser> researchers = userService.getUsersByDaaId(daaId);
1✔
185
        List<SimplifiedUser> signingOfficials = researchers.stream()
1✔
186
            .flatMap(researcher -> userService.findSOsByInstitutionId(researcher.institutionId).stream())
1✔
187
            .distinct()
1✔
188
            .collect(Collectors.toList());
1✔
189

190
        for (SimplifiedUser researcher : researchers) {
1✔
191
          emailService.sendNewDAAUploadResearcherMessage(researcher.displayName, researcher.email,
1✔
192
              dacName, previousDaaName, newDaaName, user.getUserId());
1✔
193
        }
1✔
194
        for (SimplifiedUser signingOfficial : signingOfficials) {
1✔
195
          emailService.sendNewDAAUploadSOMessage(signingOfficial.displayName, signingOfficial.email,
1✔
196
              dacName, previousDaaName, newDaaName, user.getUserId());
1✔
197
        }
1✔
198
      }
199
    } catch (Exception e) {
1✔
200
      logException(e);
1✔
201
      throw(e);
1✔
202
    }
1✔
203
  }
1✔
204

205
  public InputStream findFileById(Integer daaId) {
206
    DataAccessAgreement daa = daaDAO.findById(daaId);
1✔
207
    if (daa != null) {
1✔
208
      FileStorageObject file = daa.getFile();
1✔
209
      if (file != null) {
1✔
210
        return gcsService.getDocument(file.getBlobId().getName());
1✔
211
      }
212
    }
213
    throw new NotFoundException("Could not find DAA File with the provided ID: " + daaId);
1✔
214
  }
215

216
  public List<DataAccessAgreement> findDAAsInJsonArray(String json, String arrayKey) {
217
    List<JsonElement> jsonElementList;
218
    try {
219
      JsonObject jsonObject = new Gson().fromJson(json, JsonObject.class);
1✔
220
      jsonElementList = jsonObject.getAsJsonArray(arrayKey).asList();
1✔
221
    } catch (Exception e) {
1✔
222
      throw new BadRequestException("Invalid JSON or missing array with key: " + arrayKey);
1✔
223
    }
1✔
224
    return jsonElementList.stream().distinct().map(e -> findById(e.getAsInt())).toList();
1✔
225
  }
226

227
  public void deleteDaa(Integer daaId) {
228
    DataAccessAgreement daa = daaDAO.findById(daaId);
1✔
229
    if (daa != null) {
1✔
230
      daaDAO.deleteDaa(daaId);
1✔
231
    } else {
232
      throw new NotFoundException("Could not find DAA with the provided ID: " + daaId);
1✔
233
    }
234
  }
1✔
235
}
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