Skip to content

Commit

Permalink
Merge pull request #3 from reapit/feature/cld-664-config-serverless
Browse files Browse the repository at this point in the history
feature/cld 664 config serverless
  • Loading branch information
duong-se authored Jan 8, 2020
2 parents dc90f9b + 19e7e02 commit 77b14ab
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 41 deletions.
1 change: 1 addition & 0 deletions env.example.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dev:
COGNITO_USERPOOL_ID: "<<YOUR KEY>>"
MARKET_PLACE_URL: "<YOUR MARKET_PLACE URL>"
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
"prepublish": "yarn test && yarn build",
"prebuild": "rimraf dist && rimraf public",
"build": "tsc --p tsconfig.legacy.json && cp -rf ./src/mailer/templates/ejs ./public/mailer/templates/ejs",
"serverless": "serverless deploy",
"deploy": "CI=true yarn lint && yarn build && yarn test && yarn serverless"
"deploy:dev": "cross-env CI=true && yarn lint && yarn build && yarn test && serverless deploy --stage dev",
"deploy:prod": "cross-env CI=true && yarn lint && yarn build && yarn test && serverless deploy --stage prod"
},
"repository": {
"type": "git",
Expand All @@ -35,6 +35,7 @@
"@types/aws-lambda": "^8.10.39",
"@types/ejs": "^2.7.0",
"@types/jest": "~24.0.15",
"cross-env": "^6.0.3",
"husky": "~3.0.0",
"jest": "~24.8.0",
"lint-staged": "~9.2.0",
Expand Down
41 changes: 36 additions & 5 deletions serverless.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,48 @@
service: cognito-auth-api-dev-dev-mailer
service: cognito-mailer
custom: ${file(./env.yml)}
provider:
name: aws
runtime: nodejs10.x
stage: dev
stage: ${opt:stage, 'dev'}
region: eu-west-2
deploymentBucket:
name: cognito.mailer.${self:provider.stage}
blockPublicAccess: false
environment:
COGNITO_USERPOOL_ID: ${self:custom.${self:provider.stage}.COGNITO_USERPOOL_ID}
MARKET_PLACE_URL: ${self:custom.${self:provider.stage}.MARKET_PLACE_URL}
package:
include:
- public/**
exclude:
- .git/**
- .github/**
- .serverless/**
- coverage/**
- node_modules/**
- src/**
- .gitignore
- .env.example.yml
- .env.yml
- package.json
- README.md
- serverless.yml
- tsconfig.json
- tsconfig.legacy.json
- tslint.json

functions:
mailer:
handler: public/app.mailHandler
forgotPasswordHandler:
handler: public/app.forgotPasswordHandler
events:
- cognitoUserPool:
pool: ${self:custom.${self:provider.stage}.COGNITO_USERPOOL_ID}
trigger: CustomMessage
existing: true
existing: true
confirmRegistrationHandler:
handler: public/app.confirmRegistrationHandler
events:
- cognitoUserPool:
pool: ${self:custom.${self:provider.stage}.COGNITO_USERPOOL_ID}
trigger: CustomMessage
existing: true
9 changes: 6 additions & 3 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { CognitoUserPoolTriggerHandler } from 'aws-lambda'
import { customMailer } from './mailer/custom-mailer'
import { sendForgotPasswordMail, sendConfirmRegistrationMail } from './mailer/custom-mailer'

export const mailHandler: CognitoUserPoolTriggerHandler = (event, context, callback) =>
customMailer(event, context, callback)
export const forgotPasswordHandler: CognitoUserPoolTriggerHandler = (event, context, callback) =>
sendForgotPasswordMail(event, context, callback)

export const confirmRegistrationHandler: CognitoUserPoolTriggerHandler = (event, context, callback) =>
sendConfirmRegistrationMail(event, context, callback)
54 changes: 46 additions & 8 deletions src/mailer/__tests__/custom-mailer.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { customMailer } from '../custom-mailer'
import { sendForgotPasswordMail, sendConfirmRegistrationMail } from '../custom-mailer'
import { CognitoUserPoolTriggerEvent, Context } from 'aws-lambda'
import { confirmRegistrationTemplate, forgotPasswordTemplate } from '../templates/index'

const context = {} as Context

describe('customMailer', () => {
describe('sendForgotPasswordMail', () => {
it('should just call the callback with the event if called when userPool does not match', async () => {
process.env.COGNITO_USERPOOL_ID = 'SOME_ID'
const callback = jest.fn()
Expand All @@ -15,7 +15,7 @@ describe('customMailer', () => {
request: {}
} as CognitoUserPoolTriggerEvent

await customMailer(event, context, callback)
await sendForgotPasswordMail(event, context, callback)
expect(event.response).toEqual({})
expect(callback).toHaveBeenCalledWith(null, event)
})
Expand All @@ -30,13 +30,14 @@ describe('customMailer', () => {
request: {}
} as CognitoUserPoolTriggerEvent

await customMailer(event, context, callback)
await sendForgotPasswordMail(event, context, callback)
expect(event.response).toEqual({})
expect(callback).toHaveBeenCalledWith(null, event)
})

it('should call the callback with an updated event if the trigger source is CustomMessage_ForgotPassword', async () => {
process.env.COGNITO_USERPOOL_ID = 'SOME_ID'
process.env.MARKET_PLACE_URL = 'SOME_URL'
const callback = jest.fn()
const event = {
triggerSource: 'CustomMessage_ForgotPassword',
Expand All @@ -50,20 +51,57 @@ describe('customMailer', () => {
}
} as Partial<CognitoUserPoolTriggerEvent>

await customMailer(event as CognitoUserPoolTriggerEvent, context, callback)
await sendForgotPasswordMail(event as CognitoUserPoolTriggerEvent, context, callback)
expect(event.response).toEqual({
emailSubject: 'Reapit Foundations: Forgotten Password',
emailMessage: await forgotPasswordTemplate({
verificationCode: event.request?.codeParameter as string,
userName: event.request?.userAttributes.email as string,
url: 'https://dev.marketplace.reapit.com/developer/reset-password'
url: 'SOME_URL/developer/reset-password'
})
})
expect(callback).toHaveBeenCalledWith(null, event)
})

afterEach(() => {
jest.resetAllMocks()
})
})

describe('sendConfirmRegistrationMail', () => {
it('should just call the callback with the event if called when userPool does not match', async () => {
process.env.COGNITO_USERPOOL_ID = 'SOME_ID'
const callback = jest.fn()
const event = {
triggerSource: 'CustomMessage_ForgotPassword',
userPoolId: 'SOME_OTHER_ID',
response: {},
request: {}
} as CognitoUserPoolTriggerEvent

await sendConfirmRegistrationMail(event, context, callback)
expect(event.response).toEqual({})
expect(callback).toHaveBeenCalledWith(null, event)
})

it('should just call the callback with the event if the userPool matches but no trigger source match', async () => {
process.env.COGNITO_USERPOOL_ID = 'SOME_ID'
const callback = jest.fn()
const event = {
triggerSource: 'CreateAuthChallenge_Authentication',
userPoolId: process.env.COGNITO_USERPOOL_ID,
response: {},
request: {}
} as CognitoUserPoolTriggerEvent

await sendConfirmRegistrationMail(event, context, callback)
expect(event.response).toEqual({})
expect(callback).toHaveBeenCalledWith(null, event)
})

it('should call the callback with an updated event if the trigger source is CustomMessage_SignUp', async () => {
process.env.COGNITO_USERPOOL_ID = 'SOME_ID'
process.env.MARKET_PLACE_URL = 'SOME_URL'
const callback = jest.fn()
const event = {
triggerSource: 'CustomMessage_SignUp',
Expand All @@ -77,12 +115,12 @@ describe('customMailer', () => {
}
} as Partial<CognitoUserPoolTriggerEvent>

await customMailer(event as CognitoUserPoolTriggerEvent, context, callback)
await sendConfirmRegistrationMail(event as CognitoUserPoolTriggerEvent, context, callback)
expect(event.response).toEqual({
emailSubject: 'Welcome to Reapit Foundations',
emailMessage: await confirmRegistrationTemplate({
userName: event.request?.userAttributes.email as string,
url: 'https://dev.marketplace.reapit.com/register/confirm'
url: 'SOME_URL/register/confirm'
})
})
expect(callback).toHaveBeenCalledWith(null, event)
Expand Down
44 changes: 21 additions & 23 deletions src/mailer/custom-mailer.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
import { CognitoUserPoolTriggerHandler } from 'aws-lambda'
import { forgotPasswordTemplate, confirmRegistrationTemplate } from './templates/index'

export const customMailer: CognitoUserPoolTriggerHandler = async (event, _context, callback) => {
if (event.userPoolId === process.env.COGNITO_USERPOOL_ID) {
switch (event.triggerSource) {
case 'CustomMessage_ForgotPassword':
event.response.emailSubject = 'Reapit Foundations: Forgotten Password'
// TODO will replace by env
const resetPasswordUrl = 'https://dev.marketplace.reapit.com/developer/reset-password'
event.response.emailMessage = await forgotPasswordTemplate({
verificationCode: event.request.codeParameter as string,
userName: event.request.userAttributes.email,
url: resetPasswordUrl
})
break
case 'CustomMessage_SignUp':
event.response.emailSubject = 'Welcome to Reapit Foundations'
// TODO will replace by env
const confirmRegistrationUrl = 'https://dev.marketplace.reapit.com/register/confirm'
event.response.emailMessage = await confirmRegistrationTemplate({
userName: event.request.userAttributes.email,
url: confirmRegistrationUrl
})
break
}
export const sendForgotPasswordMail: CognitoUserPoolTriggerHandler = async (event, _context, callback) => {
if (event.userPoolId === process.env.COGNITO_USERPOOL_ID && event.triggerSource === 'CustomMessage_ForgotPassword') {
event.response.emailSubject = 'Reapit Foundations: Forgotten Password'
const resetPasswordUrl = `${process.env.MARKET_PLACE_URL}/developer/reset-password`
event.response.emailMessage = await forgotPasswordTemplate({
verificationCode: event.request.codeParameter as string,
userName: event.request.userAttributes.email,
url: resetPasswordUrl
})
}
callback(null, event)
}

export const sendConfirmRegistrationMail: CognitoUserPoolTriggerHandler = async (event, _context, callback) => {
if (event.userPoolId === process.env.COGNITO_USERPOOL_ID && event.triggerSource === 'CustomMessage_SignUp') {
event.response.emailSubject = 'Welcome to Reapit Foundations'
const confirmRegistrationUrl = `${process.env.MARKET_PLACE_URL}/register/confirm`
event.response.emailMessage = await confirmRegistrationTemplate({
userName: event.request.userAttributes.email,
url: confirmRegistrationUrl
})
}
callback(null, event)
}
40 changes: 40 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,13 @@ cosmiconfig@^5.2.1:
js-yaml "^3.13.1"
parse-json "^4.0.0"

cross-env@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941"
integrity sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==
dependencies:
cross-spawn "^7.0.0"

cross-spawn@^6.0.0, cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
Expand All @@ -990,6 +997,15 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5:
shebang-command "^1.2.0"
which "^1.2.9"

cross-spawn@^7.0.0:
version "7.0.1"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14"
integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"

[email protected], "cssom@>= 0.3.2 < 0.4.0":
version "0.3.8"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
Expand Down Expand Up @@ -3280,6 +3296,11 @@ path-key@^3.0.0:
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.0.tgz#99a10d870a803bdd5ee6f0470e58dfcd2f9a54d3"
integrity sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==

path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==

path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
Expand Down Expand Up @@ -3737,11 +3758,23 @@ shebang-command@^1.2.0:
dependencies:
shebang-regex "^1.0.0"

shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"

shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=

shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==

shellwords@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
Expand Down Expand Up @@ -4385,6 +4418,13 @@ which@^1.2.9, which@^1.3.0:
dependencies:
isexe "^2.0.0"

which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"

wide-align@^1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
Expand Down

0 comments on commit 77b14ab

Please sign in to comment.