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

DataBiosphere / consent / #6304

11 Aug 2025 01:53PM UTC coverage: 83.331% (+0.005%) from 83.326%
#6304

push

web-flow
DT-2087: New admin api to find emails by the user id (#2634)

3 of 4 new or added lines in 2 files covered. (75.0%)

10908 of 13090 relevant lines covered (83.33%)

0.83 hits per line

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

56.57
/src/main/java/org/broadinstitute/consent/http/service/EmailService.java
1
package org.broadinstitute.consent.http.service;
2

3
import com.google.common.annotations.VisibleForTesting;
4
import com.google.inject.Inject;
5
import com.sendgrid.Response;
6
import com.sendgrid.helpers.mail.Mail;
7
import com.sendgrid.helpers.mail.objects.Content;
8
import com.sendgrid.helpers.mail.objects.Email;
9
import freemarker.template.Template;
10
import freemarker.template.TemplateException;
11
import java.io.IOException;
12
import java.io.StringWriter;
13
import java.io.Writer;
14
import java.time.Instant;
15
import java.util.Date;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.Objects;
19
import javax.annotation.Nullable;
20
import org.broadinstitute.consent.http.configurations.ConsentConfiguration;
21
import org.broadinstitute.consent.http.db.MailMessageDAO;
22
import org.broadinstitute.consent.http.db.UserDAO;
23
import org.broadinstitute.consent.http.enumeration.EmailType;
24
import org.broadinstitute.consent.http.mail.SendGridAPI;
25
import org.broadinstitute.consent.http.mail.freemarker.FreeMarkerTemplateHelper;
26
import org.broadinstitute.consent.http.mail.message.DACMembersDARRADARApprovedMessage;
27
import org.broadinstitute.consent.http.mail.message.DaaRequestMessage;
28
import org.broadinstitute.consent.http.mail.message.DarExpirationReminderMessage;
29
import org.broadinstitute.consent.http.mail.message.DarExpiredMessage;
30
import org.broadinstitute.consent.http.mail.message.DataCustodianApprovalMessage;
31
import org.broadinstitute.consent.http.mail.message.DatasetApprovedMessage;
32
import org.broadinstitute.consent.http.mail.message.DatasetDeniedMessage;
33
import org.broadinstitute.consent.http.mail.message.DatasetSubmittedMessage;
34
import org.broadinstitute.consent.http.mail.message.MailMessage;
35
import org.broadinstitute.consent.http.mail.message.NewCaseMessage;
36
import org.broadinstitute.consent.http.mail.message.NewDAAUploadResearcherMessage;
37
import org.broadinstitute.consent.http.mail.message.NewDAAUploadSOMessage;
38
import org.broadinstitute.consent.http.mail.message.NewDARRequestMessage;
39
import org.broadinstitute.consent.http.mail.message.NewLibraryCardIssuedMessage;
40
import org.broadinstitute.consent.http.mail.message.NewProgressReportCaseMessage;
41
import org.broadinstitute.consent.http.mail.message.NewProgressReportRequestMessage;
42
import org.broadinstitute.consent.http.mail.message.NewResearcherLibraryRequestMessage;
43
import org.broadinstitute.consent.http.mail.message.ReminderMessage;
44
import org.broadinstitute.consent.http.mail.message.ResearcherApprovedProgressReportMessage;
45
import org.broadinstitute.consent.http.mail.message.ResearcherCloseoutCompletedMessage;
46
import org.broadinstitute.consent.http.mail.message.ResearcherDarApprovedMessage;
47
import org.broadinstitute.consent.http.mail.message.SoDARApproved;
48
import org.broadinstitute.consent.http.mail.message.SoDARSubmitted;
49
import org.broadinstitute.consent.http.mail.message.SoPRApproved;
50
import org.broadinstitute.consent.http.mail.message.SoPRSubmitted;
51
import org.broadinstitute.consent.http.mail.message.SubmittedCloseoutMessage;
52
import org.broadinstitute.consent.http.models.Dataset;
53
import org.broadinstitute.consent.http.models.User;
54
import org.broadinstitute.consent.http.models.Vote;
55
import org.broadinstitute.consent.http.models.dto.DatasetMailDTO;
56
import org.broadinstitute.consent.http.util.ConsentLogger;
57

58
public class EmailService implements ConsentLogger {
59

60
  private final UserDAO userDAO;
61
  private final MailMessageDAO emailDAO;
62
  private final FreeMarkerTemplateHelper templateHelper;
63
  private final SendGridAPI sendGridAPI;
64
  private final String fromAccount;
65
  private final String serverUrl;
66

67
  @Inject
68
  public EmailService(
69
      UserDAO userDAO,
70
      MailMessageDAO emailDAO,
71
      SendGridAPI sendGridAPI,
72
      FreeMarkerTemplateHelper helper,
73
      ConsentConfiguration config) {
1✔
74
    this.userDAO = userDAO;
1✔
75
    this.templateHelper = helper;
1✔
76
    this.emailDAO = emailDAO;
1✔
77
    this.sendGridAPI = sendGridAPI;
1✔
78
    this.serverUrl = config.getServicesConfiguration().getLocalURL();
1✔
79
    this.fromAccount = config.getMailConfiguration().getGoogleAccount();
1✔
80
  }
1✔
81

82
  /**
83
   * This method saves an email (either sent or unsent) with all available metadata from the
84
   * SendGrid response.
85
   */
86
  private void saveEmailAndResponse(
87
      @Nullable Response response,
88
      @Nullable String entityReferenceId,
89
      @Nullable Integer voteId,
90
      Integer userId,
91
      EmailType emailType,
92
      String content) {
93
    Instant now = Instant.now();
1✔
94
    Instant dateSent = (Objects.nonNull(response) && response.getStatusCode() < 400) ? now : null;
1✔
95
    emailDAO.insert(
1✔
96
        entityReferenceId,
97
        voteId,
98
        userId,
99
        emailType.getTypeInt(),
1✔
100
        dateSent,
101
        content,
102
        Objects.nonNull(response) ? response.getBody() : null,
1✔
103
        Objects.nonNull(response) ? response.getStatusCode() : null,
1✔
104
        now);
105
  }
1✔
106

107
  @VisibleForTesting
108
  protected void sendMessage(MailMessage mailMessage, Integer userId)
109
      throws IOException, TemplateException {
110
    Writer out = new StringWriter();
1✔
111
    Template template = templateHelper.getTemplate(mailMessage.getTemplateName());
1✔
112
    template.process(mailMessage.createModel(serverUrl), out);
1✔
113
    String content = out.toString();
1✔
114
    Mail message = new Mail(new Email(fromAccount), mailMessage.createSubject(),
1✔
115
        new Email(mailMessage.toUser.getEmail()), new Content("text/html", content));
1✔
116
    Response response = sendGridAPI.sendMessage(message, mailMessage.toUser.getEmail());
1✔
117
    saveEmailAndResponse(
1✔
118
        response,
119
        mailMessage.getEntityReferenceId(),
1✔
120
        mailMessage.getVoteId(),
1✔
121
        userId,
122
        mailMessage.emailType,
123
        content);
124
  }
1✔
125

126
  public List<org.broadinstitute.consent.http.models.mail.MailMessage> fetchEmailMessagesByType(
127
      EmailType emailType, Integer limit,
128
      Integer offset) {
129
    return emailDAO.fetchMessagesByType(emailType.getTypeInt(), limit, offset);
1✔
130
  }
131

132
  public List<org.broadinstitute.consent.http.models.mail.MailMessage> fetchEmailMessagesByUserId(
133
      Integer userId, Integer limit, Integer offset) {
NEW
134
    return emailDAO.fetchMessagesByUserId(userId, limit, offset);
×
135
  }
136

137
  public List<org.broadinstitute.consent.http.models.mail.MailMessage> fetchEmailMessagesByCreateDate(
138
      Date start, Date end, Integer limit,
139
      Integer offset) {
140
    return emailDAO.fetchMessagesByCreateDate(start, end, limit, offset);
1✔
141
  }
142

143

144
  public void sendResearcherDarApproved(
145
      String darCode,
146
      Integer researcherId,
147
      List<DatasetMailDTO> datasets,
148
      String dataUseRestriction,
149
      boolean radarApproved)
150
      throws TemplateException, IOException {
151
    User user = userDAO.findUserById(researcherId);
×
152
    sendMessage(
×
153
        new ResearcherDarApprovedMessage(user, darCode, datasets, dataUseRestriction, radarApproved), researcherId);
154
  }
×
155

156
  public void sendResearcherProgressReportApproved(
157
      String darCode,
158
      Integer researcherId,
159
      List<DatasetMailDTO> datasets,
160
      String dataUseRestriction)
161
      throws TemplateException, IOException {
162
    User user = userDAO.findUserById(researcherId);
×
163
    sendMessage(
×
164
        new ResearcherApprovedProgressReportMessage(user, darCode, datasets, dataUseRestriction), researcherId);
165
  }
×
166

167
  public void sendDataCustodianApprovalMessage(
168
      User custodian,
169
      String darCode,
170
      List<DatasetMailDTO> datasets,
171
      String dataDepositorName,
172
      String researcherEmail,
173
      boolean radarApproved)
174
      throws TemplateException, IOException {
175
    sendMessage(
×
176
        new DataCustodianApprovalMessage(
177
            custodian, darCode, datasets, dataDepositorName, researcherEmail, radarApproved),
178
        custodian.getUserId());
×
179
  }
×
180

181
  public void sendDatasetSubmittedMessage(
182
      User dacChair, User dataSubmitter, String dacName, String datasetName)
183
      throws TemplateException, IOException {
184
    sendMessage(
1✔
185
        new DatasetSubmittedMessage(dacChair, dataSubmitter.getDisplayName(), datasetName, dacName),
1✔
186
        dacChair.getUserId());
1✔
187
  }
1✔
188

189
  public void sendDatasetApprovedMessage(User user, String dacName, String datasetName)
190
      throws TemplateException, IOException {
191
    sendMessage(new DatasetApprovedMessage(user, dacName, datasetName), user.getUserId());
×
192
  }
×
193

194
  public void sendDatasetDeniedMessage(
195
      User user, String dacName, String datasetName, String dacEmail)
196
      throws TemplateException, IOException {
197
    sendMessage(new DatasetDeniedMessage(user, dacName, datasetName, dacEmail), user.getUserId());
×
198
  }
×
199

200
  public void sendNewResearcherMessage(User researcher, User signingOfficial)
201
      throws TemplateException, IOException {
202
    sendMessage(
1✔
203
        new NewResearcherLibraryRequestMessage(signingOfficial, researcher),
204
        researcher.getUserId());
1✔
205
  }
1✔
206

207
  public void sendDaaRequestMessage(
208
      User signingOfficial, User requestUser, String daaName, Integer daaId)
209
      throws TemplateException, IOException {
210
    sendMessage(
1✔
211
        new DaaRequestMessage(signingOfficial, requestUser, daaName, daaId),
212
        requestUser.getUserId());
1✔
213
  }
1✔
214

215
  public void sendNewDAAUploadSOMessage(
216
      User signingOfficial,
217
      String dacName,
218
      String previousDaaName,
219
      String newDaaName,
220
      Integer userId)
221
      throws TemplateException, IOException {
222
    sendMessage(
1✔
223
        new NewDAAUploadSOMessage(signingOfficial, dacName, previousDaaName, newDaaName), userId);
224
  }
1✔
225

226
  public void sendNewDAAUploadResearcherMessage(
227
      User researcher, String dacName, String previousDaaName, String newDaaName, Integer userId)
228
      throws TemplateException, IOException {
229
    sendMessage(
1✔
230
        new NewDAAUploadResearcherMessage(
231
            researcher, dacName, previousDaaName, newDaaName),
232
        userId);
233
  }
1✔
234

235
  public void sendDarNewCollectionElectionMessage(List<User> users, String darCode)
236
      throws IOException, TemplateException {
237
    String electionType = "Data Access Request";
×
238
    for (User user : users) {
×
239
      sendMessage(new NewCaseMessage(user, darCode, electionType), user.getUserId());
×
240
    }
×
241
  }
×
242

243
  public void sendProgressReportNewCollectionElectionMessage(List<User> users, String darCode)
244
      throws IOException, TemplateException {
245
    for (User user : users) {
×
246
      sendMessage(new NewProgressReportCaseMessage(user, darCode), user.getUserId());
×
247
    }
×
248
  }
×
249

250
  public void sendNewDARRequestEmail(
251
      User user, Map<String, List<String>> sendList, String researcherName, String darCode)
252
      throws TemplateException, IOException {
253
        sendMessage(new NewDARRequestMessage(user, darCode, sendList, researcherName),
×
254
        user.getUserId());
×
255
  }
×
256

257
  public void sendNewProgressReportRequestEmail(
258
      User user, Map<String, List<String>> sendList, String researcherName, String darCode, String referenceId)
259
      throws TemplateException, IOException {
260
      sendMessage(new NewProgressReportRequestMessage(user, darCode, referenceId, sendList, researcherName),
×
261
        user.getUserId());
×
262
  }
×
263

264
  /**
265
   * Send a message to a Signing Official that a new Data Access Request has been submitted.
266
   *
267
   * @param user The user to send the message to
268
   * @param darCode The Data Access Request code which is submitted
269
   * @param researcher The researcher whose DAR has been submitted
270
   * @param referenceId The reference ID of the DAR
271
   * @param datasets The datasets associated with the DAR
272
   * @throws TemplateException Template processing exception
273
   * @throws IOException IOException when processing the template or sending the email
274
   */
275
  public void sendNewSoDARSubmittedEmail(User user, String darCode, User researcher, String referenceId, List<Dataset> datasets)
276
      throws TemplateException, IOException {
277
        sendMessage(new SoDARSubmitted(user, darCode, researcher, referenceId, datasets),
×
278
        user.getUserId());
×
279
  }
×
280

281
  /**
282
   * Send a message to a Signing Official that a new progress report has been submitted.
283
   *
284
   * @param user The user to send the message to
285
   * @param darCode The Data Access Request code for which the progress report is submitted
286
   * @param researcher The researcher whose progress report has been submitted
287
   * @param referenceId The reference ID of the progress report
288
   * @param datasets The datasets associated with the progress report
289
   * @throws TemplateException Template processing exception
290
   * @throws IOException IOException when processing the template or sending the email
291
   */
292
  public void sendNewSoProgressReportSubmittedEmail(User user, String darCode, User researcher, String referenceId, List<Dataset> datasets)
293
      throws TemplateException, IOException {
294
      sendMessage(new SoPRSubmitted(user, darCode, researcher, referenceId, datasets),
×
295
        user.getUserId());
×
296
  }
×
297

298
  /**
299
   * Send a message to a Signing Official that a new Data Access Request has been approved.
300
   *
301
   * @param user The user to send the message to
302
   * @param darCode The Data Access Request code which is approved
303
   * @param researcher The researcher whose DAR has been approved
304
   * @param referenceId The reference ID of the DAR
305
   * @param datasets The datasets associated with the DAR
306
   * @param dataUseRestriction The data use restriction associated with the datasets in the DAR
307
   * @throws TemplateException Template processing exception
308
   * @throws IOException IOException when processing the template or sending the email
309
   */
310
  public void sendNewSoDARApprovedEmail(User user, String darCode, User researcher, String referenceId, List<Dataset> datasets, String dataUseRestriction, boolean radarApproved)
311
      throws TemplateException, IOException {
312
        sendMessage(new SoDARApproved(user, darCode, researcher, referenceId, datasets, dataUseRestriction, radarApproved),
×
313
        user.getUserId());
×
314
  }
×
315

316
  /**
317
   * Send a message to a Signing Official that a new progress report has been approved.
318
   *
319
   * @param user The user to send the message to
320
   * @param darCode The Data Access Request code for which the progress report is approved
321
   * @param researcher The researcher whose progress report has been approved
322
   * @param referenceId The reference ID of the progress report
323
   * @param datasets The datasets associated with the progress report
324
   * @param dataUseRestriction The data use restriction associated with the datasets in the progress report
325
   * @throws TemplateException Template processing exception
326
   * @throws IOException IOException when processing the template or sending the email
327
   */
328
  public void sendNewSoProgressReportApprovedEmail(User user, String darCode, User researcher, String referenceId, List<Dataset> datasets, String dataUseRestriction)
329
      throws TemplateException, IOException {
330
      sendMessage(new SoPRApproved(user, darCode, researcher, referenceId, datasets, dataUseRestriction),
×
331
        user.getUserId());
×
332
  }
×
333

334
  /**
335
   * Send a message to a researcher that their data access request has expired.
336
   *
337
   * @param researcher  the researcher to send the message to
338
   * @param darCode     the data access request code that's expired
339
   * @param userId      the user id of the person sending the message
340
   * @param referenceId the data access request reference id that's expired
341
   */
342
  public void sendDarExpiredMessage(User researcher, String darCode, Integer userId,
343
      String referenceId)
344
      throws TemplateException, IOException {
345
    sendMessage(new DarExpiredMessage(researcher, darCode, referenceId), userId);
1✔
346
  }
1✔
347

348
  /**
349
   * Remind the user that their data access request is about to expire.
350
   *
351
   * @param user        the user to send the message to
352
   * @param darCode     the data access request code that's about to expire
353
   * @param userId      the user id of the person sending the message
354
   * @param referenceId the data access request reference id that is expiring
355
   */
356
  public void sendDarExpirationReminderMessage(User user, String darCode, Integer userId,
357
      String referenceId)
358
      throws TemplateException, IOException {
359
    sendMessage(new DarExpirationReminderMessage(user, darCode, referenceId), userId);
1✔
360
  }
1✔
361

362
  public void sendReminderMessage(User user, Vote vote, String darCode, String electionType, String url)
363
      throws TemplateException, IOException {
364
    sendMessage(new ReminderMessage(user, vote, darCode, electionType, url), user.getUserId());
×
365
  }
×
366

367
  /**
368
   * Send a message to a user that their closeout has been completed.
369
   *
370
   * @param user        the user to send the message to
371
   * @param darCode     the data access request code for which closeout is completed
372
   * @param referenceId the data access request reference id for which closeout is completed
373
   */
374
  public void sendResearcherCloseoutCompletedMessage(User user, String darCode, String referenceId)
375
      throws TemplateException, IOException {
376
    sendMessage(new ResearcherCloseoutCompletedMessage(user, darCode, referenceId),
1✔
377
        user.getUserId());
1✔
378
  }
1✔
379

380
  /**
381
   * Send a message to a Signing Official or a DAC member that a closeout has been submitted for
382
   * review.
383
   *
384
   * @param toUser      The user to send the message to
385
   * @param darId       The Data Access Request ID associated with the closeout
386
   * @param referenceId The Reference ID of the closeout request
387
   * @param closeoutUrl The URL to the closeout request for review
388
   * @throws TemplateException Template processing exception
389
   * @throws IOException       IOException when processing the template or sending the email
390
   */
391
  public void sendSubmittedCloseoutMessage(User toUser, String darId, String referenceId, String closeoutUrl)
392
      throws TemplateException, IOException {
393
    sendMessage(new SubmittedCloseoutMessage(toUser, darId, referenceId, closeoutUrl), toUser.getUserId());
1✔
394
  }
1✔
395

396
  /**
397
   * Send a message to the user when they are issued a library card
398
   *
399
   * @param toUser The user to send the message to
400
   * @throws TemplateException Template processing exception
401
   * @throws IOException IOException when processing the template or sending the email
402
   */
403
  public void sendNewLibraryCardIssuedMessage(User toUser) throws TemplateException, IOException {
404
    sendMessage(new NewLibraryCardIssuedMessage(toUser), toUser.getUserId());
1✔
405
  }
1✔
406

407
  public void sendNewDARRADARApprovalToDAC(
408
      User dacMember,
409
      String darCode,
410
      String referenceId,
411
      List<DatasetMailDTO> datasetList,
412
      User researcher)
413
      throws TemplateException, IOException {
414
    sendMessage(
1✔
415
        new DACMembersDARRADARApprovedMessage(
416
            dacMember, darCode, researcher, referenceId, datasetList),
417
        dacMember.getUserId());
1✔
418
  }
1✔
419
}
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