Skip to content

Commit 7400a6f

Browse files
authored
feat: send email notifications to DAU newly added to a proposal (#1626)
1 parent 2288dbf commit 7400a6f

4 files changed

Lines changed: 71 additions & 0 deletions

File tree

apps/backend/src/eventHandlers/email/emailTemplateId.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ export enum EmailTemplateId {
1818
CALL_CREATED_EMAIL = 'call-created-email',
1919
FEEDBACK_REQUEST = 'feedback-request',
2020
CO_PROPOSER_INVITE = 'co-proposer-invite',
21+
DATA_ACCESS_USER_ADDED = 'data-access-user-added',
2122
}

apps/backend/src/eventHandlers/email/essEmailHandler.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,61 @@ export async function essEmailHandler(event: ApplicationEvent) {
350350
break;
351351
}
352352

353+
case Event.DATA_ACCESS_USERS_UPDATED: {
354+
// Only newly added users are notified; a pure removal or no-op update
355+
// carries an empty list and sends nothing.
356+
if (event.newlyAddedUserIds.length === 0) {
357+
return;
358+
}
359+
360+
const proposal = await proposalDataSource.get(event.proposalPKey);
361+
if (!proposal) {
362+
logger.logError('No proposal found when trying to send email', {
363+
proposalPKey: event.proposalPKey,
364+
event,
365+
});
366+
367+
return;
368+
}
369+
370+
const invitedUsers = await userDataSource.getBasicUsersInfo(
371+
event.newlyAddedUserIds
372+
);
373+
374+
for (const user of invitedUsers) {
375+
mailService
376+
.sendMail({
377+
content: {
378+
template: EmailTemplateId.DATA_ACCESS_USER_ADDED,
379+
},
380+
substitution_data: {
381+
preferredname: user.preferredname,
382+
firstname: user.firstname,
383+
lastname: user.lastname,
384+
proposalTitle: proposal.title,
385+
proposalId: proposal.proposalId,
386+
},
387+
recipients: [{ address: user.email }],
388+
})
389+
.then((res) => {
390+
logger.logInfo('Email sent on data access user added', {
391+
result: res,
392+
userId: user.id,
393+
proposalPKey: event.proposalPKey,
394+
});
395+
})
396+
.catch((err: string) => {
397+
logger.logError('Could not send email on data access user added', {
398+
error: err,
399+
userId: user.id,
400+
event,
401+
});
402+
});
403+
}
404+
405+
return;
406+
}
407+
353408
case Event.FAP_REVIEWER_NOTIFIED: {
354409
const { id: reviewId, userID, proposalPk } = event.fapReview;
355410
const fapReviewer = await userDataSource.getUser(userID);

apps/backend/src/events/applicationEvents.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,9 @@ interface VisitRegistrationCancelledEvent extends GeneralEvent {
420420
interface UserDataAccessUpdatedEvent extends GeneralEvent {
421421
type: Event.DATA_ACCESS_USERS_UPDATED;
422422
proposalPKey: number;
423+
// Users newly added as data access users in this update (empty on removals
424+
// or no-op updates). Used to notify only the freshly invited users by email.
425+
newlyAddedUserIds: number[];
423426
}
424427

425428
interface ExperimentSafetyManagementDecisionSubmittedByISEvent

apps/backend/src/mutations/DataAccessUsersMutations.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ export default class DataAccessUsersMutations {
5858
);
5959
}
6060

61+
// Data access users are stored via delete-all + reinsert, so capture the
62+
// current members first to work out who is genuinely newly invited.
63+
const existingDataAccessUsers =
64+
await this.dataSource.findByProposalPk(proposalPk);
65+
const existingUserIds = new Set(
66+
existingDataAccessUsers.map((user) => user.id)
67+
);
68+
const newlyAddedUserIds = userIds.filter(
69+
(userId) => !existingUserIds.has(userId)
70+
);
71+
6172
const result = await this.dataSource.updateDataAccessUsers(
6273
proposalPk,
6374
userIds
@@ -69,6 +80,7 @@ export default class DataAccessUsersMutations {
6980
await eventBus.publish({
7081
type: Event.DATA_ACCESS_USERS_UPDATED,
7182
proposalPKey: proposalPk,
83+
newlyAddedUserIds: newlyAddedUserIds,
7284
key: 'proposalPk',
7385
loggedInUserId: agent ? agent.id : null,
7486
isRejection: false,

0 commit comments

Comments
 (0)