Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: hide other recipients #911

Merged
merged 13 commits into from
Nov 19, 2024
24 changes: 17 additions & 7 deletions api/src/services/email.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,12 +411,14 @@ export class EmailService {
listingInfo: IdDTO,
emails: string[],
appUrl: string,
jurisEmail: string,
) {
const jurisdiction = await this.getJurisdiction([jurisdictionId]);
void (await this.loadTranslations(jurisdiction));

await this.sendSES({
to: emails,
to: jurisEmail,
bcc: emails,
subject: this.polyglot.t('requestApproval.header'),
html: this.template('request-approval')({
appOptions: { listingName: listingInfo.name },
Expand All @@ -431,14 +433,16 @@ export class EmailService {
listingInfo: listingInfo,
emails: string[],
appUrl: string,
jurisEmail: string,
) {
const jurisdiction = listingInfo.juris
? await this.getJurisdiction([{ id: listingInfo.juris }])
: user.jurisdictions[0];
void (await this.loadTranslations(jurisdiction));

await this.sendSES({
to: emails,
to: jurisEmail,
bcc: emails,
subject: this.polyglot.t('changesRequested.header'),
html: this.template('changes-requested')({
appOptions: { listingName: listingInfo.name },
Expand All @@ -453,12 +457,14 @@ export class EmailService {
listingInfo: IdDTO,
emails: string[],
publicUrl: string,
jurisEmail: string,
) {
const jurisdiction = await this.getJurisdiction([jurisdictionId]);
void (await this.loadTranslations(jurisdiction));

await this.sendSES({
to: emails,
to: jurisEmail,
bcc: emails,
subject: this.polyglot.t('listingApproved.header'),
html: this.template('listing-approved')({
appOptions: { listingName: listingInfo.name },
Expand Down Expand Up @@ -615,9 +621,11 @@ export class EmailService {
listingInfo: listingInfo,
emails: string[],
appUrl: string,
jurisEmail: string,
) {
await this.sendSES({
to: emails,
to: jurisEmail,
bcc: emails,
subject: this.polyglot.t('lotteryReleased.header', {
listingName: listingInfo.name,
}),
Expand All @@ -633,13 +641,15 @@ export class EmailService {
listingInfo: listingInfo,
emails: string[],
appUrl: string,
jurisEmail: string,
) {
const jurisdiction = await this.getJurisdiction([
{ id: listingInfo.juris },
]);
void (await this.loadTranslations(jurisdiction));
await this.sendSES({
to: emails,
to: jurisEmail,
bcc: emails,
subject: this.polyglot.t('lotteryPublished.header', {
listingName: listingInfo.name,
}),
Expand All @@ -664,8 +674,8 @@ export class EmailService {
for (const language in emails) {
void (await this.loadTranslations(null, language as LanguagesEnum));
await this.sendSES({
to: emails[language],

to: jurisdiction.emailFromAddress,
bcc: emails[language],
subject: this.polyglot.t('lotteryAvailable.header', {
listingName: listingInfo.name,
}),
Expand Down
54 changes: 38 additions & 16 deletions api/src/services/listing.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,12 @@ export class ListingService implements OnModuleInit {
listingId?: string,
jurisId?: string,
getPublicUrl = false,
): Promise<{ emails: string[]; publicUrl?: string | null }> {
getEmailFromAddress = false,
): Promise<{
emails: string[];
publicUrl?: string | null;
emailFromAddress?: string | null;
}> {
// determine where clause(s)
const userRolesWhere: Prisma.UserAccountsWhereInput[] = [];
if (userRoles.includes(UserRoleEnum.admin))
Expand All @@ -381,28 +386,37 @@ export class ListingService implements OnModuleInit {
});
}

const userResults = await this.prisma.userAccounts.findMany({
include: {
jurisdictions: {
select: {
id: true,
publicUrl: getPublicUrl,
},
},
const rawUsers = await this.prisma.userAccounts.findMany({
ColinBuyck marked this conversation as resolved.
Show resolved Hide resolved
select: {
id: true,
email: true,
},
where: {
OR: userRolesWhere,
},
});

// account for users having access to multiple jurisdictions
const publicUrl = getPublicUrl
? userResults[0]?.jurisdictions?.find((juris) => juris.id === jurisId)
?.publicUrl
const rawJuris = await this.prisma.jurisdictions.findFirst({
select: {
id: true,
publicUrl: getPublicUrl,
emailFromAddress: getEmailFromAddress,
},
where: {
id: jurisId,
},
});

const publicUrl = getPublicUrl ? rawJuris?.publicUrl : null;
const emailFromAddress = getEmailFromAddress
? rawJuris?.emailFromAddress
: null;
const userEmails: string[] = [];
userResults?.forEach((user) => user?.email && userEmails.push(user.email));
return { emails: userEmails, publicUrl };

const userEmails: string[] = rawUsers?.reduce((userEmails, user) => {
if (user?.email) userEmails.push(user.email);
return userEmails;
}, []);
return { emails: userEmails, publicUrl, emailFromAddress };
}

public async listingApprovalNotify(params: {
Expand All @@ -424,12 +438,15 @@ export class ListingService implements OnModuleInit {
params.approvingRoles,
params.listingInfo.id,
params.jurisId,
false,
true,
);
await this.emailService.requestApproval(
{ id: params.jurisId },
{ id: params.listingInfo.id, name: params.listingInfo.name },
userInfo.emails,
this.configService.get('PARTNERS_PORTAL_URL'),
userInfo.emailFromAddress,
);
}
// admin updates status to changes requested when approval requires partner changes
Expand All @@ -441,6 +458,8 @@ export class ListingService implements OnModuleInit {
nonApprovingRoles,
params.listingInfo.id,
params.jurisId,
false,
true,
);
await this.emailService.changesRequested(
params.user,
Expand All @@ -451,6 +470,7 @@ export class ListingService implements OnModuleInit {
},
userInfo.emails,
this.configService.get('PARTNERS_PORTAL_URL'),
userInfo.emailFromAddress,
);
}
// check if status of active requires notification
Expand All @@ -466,12 +486,14 @@ export class ListingService implements OnModuleInit {
params.listingInfo.id,
params.jurisId,
true,
true,
);
await this.emailService.listingApproved(
{ id: params.jurisId },
{ id: params.listingInfo.id, name: params.listingInfo.name },
userInfo.emails,
userInfo.publicUrl,
userInfo.emailFromAddress,
);
}
}
Expand Down
6 changes: 6 additions & 0 deletions api/src/services/lottery.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,8 @@ export class LotteryService {
],
listing.id,
listing.jurisdictions?.id,
false,
true,
);

const publicUserEmailInfo = await this.getPublicUserEmailInfo(listing.id);
Expand All @@ -423,6 +425,7 @@ export class LotteryService {
},
partnerUserEmailInfo.emails,
this.configService.get('PARTNERS_PORTAL_URL'),
partnerUserEmailInfo.emailFromAddress,
);

await this.emailService.lotteryPublishedApplicant(
Expand Down Expand Up @@ -508,6 +511,8 @@ export class LotteryService {
],
storedListing.id,
storedListing.jurisdictionId,
false,
true,
);

await this.emailService.lotteryReleased(
Expand All @@ -518,6 +523,7 @@ export class LotteryService {
},
partnerUserEmailInfo.emails,
this.configService.get('PARTNERS_PORTAL_URL'),
partnerUserEmailInfo.emailFromAddress,
);
break;
}
Expand Down
5 changes: 5 additions & 0 deletions api/test/integration/listing.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ describe('Listing Controller Tests', () => {
let app: INestApplication;
let prisma: PrismaService;
let jurisdictionAId: string;
let jurisdictionAEmail: string;
let adminAccessToken: string;

const testEmailService = {
Expand Down Expand Up @@ -87,6 +88,7 @@ describe('Listing Controller Tests', () => {
data: jurisdictionFactory(),
});
jurisdictionAId = jurisdiction.id;
jurisdictionAEmail = jurisdiction.emailFromAddress;
await reservedCommunityTypeFactoryAll(jurisdictionAId, prisma);
await unitAccessibilityPriorityTypeFactoryAll(prisma);
const adminUser = await prisma.userAccounts.create({
Expand Down Expand Up @@ -940,6 +942,7 @@ describe('Listing Controller Tests', () => {
{ id: listing.id, name: val.name },
expect.arrayContaining([adminUser.email, jurisAdmin.email]),
process.env.PARTNERS_PORTAL_URL,
jurisdictionAEmail,
);
//ensure juris admin is not included since don't have approver permissions in alameda seed
expect(mockRequestApproval.mock.calls[0]['emails']).toEqual(
Expand Down Expand Up @@ -980,6 +983,7 @@ describe('Listing Controller Tests', () => {
{ id: listing.id, name: val.name },
expect.arrayContaining([partnerUser.email]),
jurisdictionA.publicUrl,
jurisdictionA.emailFromAddress,
);
expect(mockListingOpportunity).toBeCalledWith(
expect.objectContaining({
Expand Down Expand Up @@ -1022,6 +1026,7 @@ describe('Listing Controller Tests', () => {
{ id: listing.id, name: val.name, juris: expect.anything() },
expect.arrayContaining([partnerUser.email]),
process.env.PARTNERS_PORTAL_URL,
jurisdictionAEmail,
);
});
});
Expand Down
4 changes: 4 additions & 0 deletions api/test/integration/lottery.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ describe('Lottery Controller Tests', () => {
let cookies = '';
let adminAccessToken: string;
let jurisdictionAId: string;
let jurisdictionAEmail: string;
let unitTypeA: UnitTypes;

const testEmailService = {
Expand Down Expand Up @@ -101,6 +102,7 @@ describe('Lottery Controller Tests', () => {
data: jurisdictionFactory(),
});
jurisdictionAId = jurisdiction.id;
jurisdictionAEmail = jurisdiction.emailFromAddress;
await reservedCommunityTypeFactoryAll(jurisdictionAId, prisma);
await unitTypeFactoryAll(prisma);
unitTypeA = await unitTypeFactorySingle(prisma, UnitTypeEnum.oneBdrm);
Expand Down Expand Up @@ -895,6 +897,7 @@ describe('Lottery Controller Tests', () => {
},
expect.arrayContaining([partnerUser.email, adminUser.email]),
process.env.PARTNERS_PORTAL_URL,
jurisdictionAEmail,
);

const activityLogResult = await prisma.activityLog.findFirst({
Expand Down Expand Up @@ -1078,6 +1081,7 @@ describe('Lottery Controller Tests', () => {
},
expect.arrayContaining([partnerUser.email, adminUser.email]),
process.env.PARTNERS_PORTAL_URL,
jurisdictionAEmail,
);

expect(mockLotteryPublishedApplicant).toBeCalledWith(
Expand Down
6 changes: 3 additions & 3 deletions api/test/unit/services/email.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ describe('Testing email service', () => {

expect(sendMock).toHaveBeenCalled();
const emailMock = sendMock.mock.calls[0][0];
expect(emailMock.to).toEqual(emailArr);
expect(emailMock.bcc).toEqual(emailArr);
expect(emailMock.subject).toEqual('Listing approval requested');
expect(emailMock.html).toMatch(
`<img src="https://housingbayarea.mtc.ca.gov/images/doorway-logo.png" alt="Bloom Housing Portal" width="300" height="65" class="header-image"/>`,
Expand Down Expand Up @@ -378,7 +378,7 @@ describe('Testing email service', () => {

expect(sendMock).toHaveBeenCalled();
const emailMock = sendMock.mock.calls[0][0];
expect(emailMock.to).toEqual(emailArr);
expect(emailMock.bcc).toEqual(emailArr);
expect(emailMock.subject).toEqual('Listing changes requested');
expect(emailMock.html).toMatch(
`<img src="https://housingbayarea.mtc.ca.gov/images/doorway-logo.png" alt="Bloom Housing Portal" width="300" height="65" class="header-image"/>`,
Expand Down Expand Up @@ -423,7 +423,7 @@ describe('Testing email service', () => {

expect(sendMock).toHaveBeenCalled();
const emailMock = sendMock.mock.calls[0][0];
expect(emailMock.to).toEqual(emailArr);
expect(emailMock.bcc).toEqual(emailArr);
expect(emailMock.subject).toEqual('New published listing');
expect(emailMock.html).toMatch(
`<img src="https://housingbayarea.mtc.ca.gov/images/doorway-logo.png" alt="Bloom Housing Portal" width="300" height="65" class="header-image"/>`,
Expand Down
Loading
Loading