From 1a472582666fc0f62f4defa08d2cc45f4c55e759 Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Wed, 29 Oct 2025 20:10:40 +0100 Subject: [PATCH 1/4] Allow for more OIDC providers and make sure scheduled function works initially, even without Twilio credentials --- functions/src/functions/blocking.ts | 36 ++++++++++++++----- .../src/services/trigger/triggerService.ts | 32 ++++++++++++++--- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/functions/src/functions/blocking.ts b/functions/src/functions/blocking.ts index 424725c8..b59d1f36 100644 --- a/functions/src/functions/blocking.ts +++ b/functions/src/functions/blocking.ts @@ -16,6 +16,7 @@ import { privilegedServiceAccount } from "./helpers.js"; import { Env } from "../env.js"; import { Flags } from "../flags.js"; import { getServiceFactory } from "../services/factory/getServiceFactory.js"; +import z from "zod"; export const beforeUserCreatedFunction = beforeUserCreated( { @@ -47,11 +48,30 @@ export const beforeUserCreatedFunction = beforeUserCreated( return { customClaims: {} }; } - logger.info( - `${userId}: About to check email address: ${event.data.email}.`, - ); + let emailAddress: string | undefined = undefined; + try { + const credentialClaims = event.credential?.claims ?? {}; + emailAddress = z + .string() + .optional() + .parse( + event.data.email ?? + credentialClaims["upn"] ?? + credentialClaims["unique_name"], + ); + } catch (error: unknown) { + logger.error( + `${userId}: Email address validation failed ${String(error)}.`, + ); + throw new https.HttpsError( + "invalid-argument", + "Email address validation failed.", + ); + } - if (event.data.email === undefined) { + logger.info(`${userId}: About to check email address: ${emailAddress}.`); + + if (emailAddress === undefined) { logger.error(`Email address not set.`); throw new https.HttpsError( "invalid-argument", @@ -77,14 +97,12 @@ export const beforeUserCreatedFunction = beforeUserCreated( ); } - logger.info( - `${userId}: About to get invitation by code: ${event.data.email}.`, - ); + logger.info(`${userId}: About to get invitation by code: ${emailAddress}.`); - const invitation = await userService.getInvitationByCode(event.data.email); + const invitation = await userService.getInvitationByCode(emailAddress); if (invitation?.content === undefined) { logger.error( - `${userId}: No valid invitation code found for user with email ${event.data.email}.`, + `${userId}: No valid invitation code found for user with email ${emailAddress}.`, ); throw new https.HttpsError( "not-found", diff --git a/functions/src/services/trigger/triggerService.ts b/functions/src/services/trigger/triggerService.ts index 1fd9f1b9..2c5b5f9d 100644 --- a/functions/src/services/trigger/triggerService.ts +++ b/functions/src/services/trigger/triggerService.ts @@ -63,17 +63,41 @@ export class TriggerService { patients, messageService, now, + }).catch((error: unknown) => { + logger.error( + `everyMorning: Error adding daily reminders: ${String(error)}`, + ); }), this.addInactivityReminderMessages({ patients, now, messageService, userService, + }).catch((error: unknown) => { + logger.error( + `everyMorning: Error adding inactivity reminders: ${String(error)}`, + ); + }), + this.addAppointmentReminderMessages(now).catch((error: unknown) => { + logger.error( + `everyMorning: Error adding appointment reminders: ${String(error)}`, + ); + }), + this.completeAppointmentReminderMessages(now).catch((error: unknown) => { + logger.error( + `everyMorning: Error completing appointment reminders: ${String(error)}`, + ); + }), + this.seedStaticDataIfNeeded().catch((error: unknown) => { + logger.error( + `everyMorning: Error seeding static data: ${String(error)}`, + ); + }), + this.deleteExpiredAccounts().catch((error: unknown) => { + logger.error( + `everyMorning: Error deleting expired accounts: ${String(error)}`, + ); }), - this.addAppointmentReminderMessages(now), - this.completeAppointmentReminderMessages(now), - this.seedStaticDataIfNeeded(), - this.deleteExpiredAccounts(), ]); } From ee745c6eb0c58ab4a85d6605fbf325d457877efe Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Wed, 29 Oct 2025 20:15:32 +0100 Subject: [PATCH 2/4] Add ssoProviderId from UW --- functions/data/organizations.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/data/organizations.json b/functions/data/organizations.json index 77de2fa6..a0fe3727 100644 --- a/functions/data/organizations.json +++ b/functions/data/organizations.json @@ -25,6 +25,6 @@ "contactName": "University of Washington Study Coordinator", "phoneNumber": "", "emailAddress": "", - "ssoProviderId": "" + "ssoProviderId": "oidc.entra.uw.edu" } } From 0f913ec3400fcb19d08428a4364ce0fc7e219a3d Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Wed, 29 Oct 2025 20:16:40 +0100 Subject: [PATCH 3/4] lint:fix --- functions/src/functions/blocking.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/src/functions/blocking.ts b/functions/src/functions/blocking.ts index b59d1f36..ed4f1147 100644 --- a/functions/src/functions/blocking.ts +++ b/functions/src/functions/blocking.ts @@ -12,11 +12,11 @@ import { beforeUserCreated, beforeUserSignedIn, } from "firebase-functions/v2/identity"; +import z from "zod"; import { privilegedServiceAccount } from "./helpers.js"; import { Env } from "../env.js"; import { Flags } from "../flags.js"; import { getServiceFactory } from "../services/factory/getServiceFactory.js"; -import z from "zod"; export const beforeUserCreatedFunction = beforeUserCreated( { From 55b61c0956a93d8f7d2f7dcb030b6500e5264f98 Mon Sep 17 00:00:00 2001 From: Paul Kraft Date: Wed, 29 Oct 2025 20:19:04 +0100 Subject: [PATCH 4/4] Use less characters to describe the same thing --- functions/src/functions/blocking.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/functions/src/functions/blocking.ts b/functions/src/functions/blocking.ts index ed4f1147..25e4aa4d 100644 --- a/functions/src/functions/blocking.ts +++ b/functions/src/functions/blocking.ts @@ -50,14 +50,13 @@ export const beforeUserCreatedFunction = beforeUserCreated( let emailAddress: string | undefined = undefined; try { - const credentialClaims = event.credential?.claims ?? {}; emailAddress = z .string() .optional() .parse( event.data.email ?? - credentialClaims["upn"] ?? - credentialClaims["unique_name"], + credential.claims?.["upn"] ?? + credential.claims?.["unique_name"], ); } catch (error: unknown) { logger.error(