diff --git a/serverless/firebase.json b/serverless/firebase.json index 9153ff9..c3c54d8 100644 --- a/serverless/firebase.json +++ b/serverless/firebase.json @@ -8,6 +8,18 @@ "npm --prefix functions run build", "npm --prefix \"$RESOURCE_DIR\" run lint", "npm --prefix \"$RESOURCE_DIR\" run build" - ] + ], + "source": "functions" + }, + "emulators": { + "functions": { + "port": 5001 + }, + "firestore": { + "port": 8080 + }, + "ui": { + "enabled": true + } } } diff --git a/serverless/functions/.eslintrc.js b/serverless/functions/.eslintrc.js index 63a7f15..a4b61ac 100644 --- a/serverless/functions/.eslintrc.js +++ b/serverless/functions/.eslintrc.js @@ -30,6 +30,6 @@ module.exports = { rules: { quotes: ["error", "double"], // "import/no-unresolved": 0, - // "no-unused-vars": "disabled", + "no-unused-vars": 0, }, } diff --git a/serverless/functions/package.json b/serverless/functions/package.json index 7594e0f..29f678a 100644 --- a/serverless/functions/package.json +++ b/serverless/functions/package.json @@ -3,13 +3,13 @@ "scripts": { "lint": "eslint --ext .js,.ts .", "build": "npm run lint && tsc", - "serve": "npm run build && firebase emulators:start --only functions & tsc --watch", + "serve": "npm run build && firebase emulators:start --only functions", "shell": "npm run build && firebase functions:shell", "start": "npm run shell", "deploy": "firebase deploy --only functions", "logs": "firebase functions:log", "hotReload": "tsc --watch", - "copyModels": "cp -r ../../web/models /models" + "copyModels": "cp -r ../../web/models ./models" }, "engines": { "node": "16" diff --git a/serverless/functions/src/index.ts b/serverless/functions/src/index.ts index b7a9925..60ec134 100644 --- a/serverless/functions/src/index.ts +++ b/serverless/functions/src/index.ts @@ -14,5 +14,5 @@ export const helloWorld = functions.https.onRequest((request, response) => { import { agoraToken } from "./agora"; exports.agoraToken = agoraToken; -// import { inviteUserToTeam } from "./notifications"; -// exports.inviteUserToTeam = inviteUserToTeam; +import { inviteUserToTeam } from "./notifications"; +exports.inviteUserToTeam = inviteUserToTeam; diff --git a/serverless/functions/src/notifications.ts b/serverless/functions/src/notifications.ts index adf8808..7eb2cb0 100644 --- a/serverless/functions/src/notifications.ts +++ b/serverless/functions/src/notifications.ts @@ -1,8 +1,8 @@ /* eslint-disable no-unused-vars */ import * as functions from "firebase-functions"; +import * as admin from "firebase-admin"; import * as sgMail from "@sendgrid/mail"; - -import { TeamMember, TeamMemberStatus } from "../../../web/models/teamMember"; +import { MailDataRequired } from "@sendgrid/mail"; sgMail.setApiKey( "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" @@ -12,38 +12,92 @@ enum SendgridTemplateId { inviteTeamMember = "d-4953372ac7b94d3fa9419bad4073840f", } -class SendGridEmailMessage { - to: string; - from: string; - templateId: SendgridTemplateId; - dynamic_template_data: {}; +const SENDER_EMAIL = "arjunpatel@berkeley.edu" - constructor( - _to: string, - _from: string, - _templateId: SendgridTemplateId, - _templateData: {} - ) { - this.to = _to; - this.from = _from; - this.templateId = _templateId; - this.dynamic_template_data = _templateData; - } +// class SendGridEmailMessage { +// to: string; +// from: string = "usenirvana@gmail.com" +// templateId: SendgridTemplateId; +// dynamic_template_data: {}; + +// constructor( +// _to: string, +// _templateId: SendgridTemplateId, +// _templateData: {} +// ) { +// this.to = _to; +// this.templateId = _templateId; +// this.dynamic_template_data = _templateData; +// } +// } + +type Team = { + id: string; + name: string; + + status: string; + + allowedUserCount: number; + + companySite: string; + + createdByUserId: string; } +type TeamMember = { + id: string; + userId: string; + teamId: string; + + inviteEmailAddress: string; + invitedByUserId: string; + + role: string + status: string +} + +// onCreate of team invite to a member -> email export const inviteUserToTeam = functions.firestore .document("teamMembers/{teamMemberId}") .onCreate(async (snap, context) => { - const newTeamMember: TeamMember = snap.data() as TeamMember; - if (newTeamMember.status == TeamMemberStatus.invited) { + const newTeamMember = snap.data() as TeamMember; + + if (!newTeamMember || !newTeamMember.inviteEmailAddress) { + functions.logger.error("No team member email available") + return + } + + // only if invited will be sending invite + if (newTeamMember.status == "invited") { functions.logger.info( "New team member invited...sending email" + newTeamMember.inviteEmailAddress, { structuredData: true } - ); + ) - // send email to people + // get team information from team id + const snapshot = await admin.firestore().collection("teams").doc(newTeamMember.teamId).get() + if (!snapshot.exists) { + functions.logger.error("No team exists") + return + } + const team: Team = snapshot.data() as Team; - return; + // send email to invited person, based on the email address + const message: MailDataRequired = { + from: SENDER_EMAIL, + to: newTeamMember.inviteEmailAddress, + templateId: SendgridTemplateId.inviteTeamMember, + dynamicTemplateData: { + teamName: team.name, + subject: "Your Team is On Nirvana - " + team.name, + joinTeamUrl: "https://usenirvana.com/teams/login", + landingPageUrl: "https://usenirvana.com" + } + } + + return await sgMail.send(message) } + + return })