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

DataBiosphere / consent / #6325

13 Aug 2025 02:02PM UTC coverage: 83.342% (+0.001%) from 83.341%
#6325

push

web-flow
[DT-2112] Adjust SO PR notification when RADAR approved. (#2641)

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

10917 of 13099 relevant lines covered (83.34%)

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) {
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
      boolean radarApproved)
162
      throws TemplateException, IOException {
163
    User user = userDAO.findUserById(researcherId);
×
164
    sendMessage(
×
165
        new ResearcherApprovedProgressReportMessage(user, darCode, datasets, dataUseRestriction, radarApproved), researcherId);
166
  }
×
167

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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