diff --git a/README.md b/README.md index 4d5e2f4..4bea97e 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,13 @@ Our API is stateless and is intended to run ephemerally on serverless environmen ## Important Links +[Postman Collection](https://documenter.getpostman.com/view/26880150/2sA3BoarvB) +[GitBook Documentation](https://docs.equalify.dev/) + Production environment: https://api.equalify.dev Staging environment: https://api-staging.equalify.dev Local environment: http://localhost:3000 -Postman collection: https://documenter.getpostman.com/view/26880150/2sA3BoarvB - ## Setup 1. Clone the repository! diff --git a/package.json b/package.json index a432ae8..b21cf62 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "start:prod": "esbuild --format=esm src/**/*.ts --outdir=dist && nodemon --env-file=.env.production dist/app.js", "start:staging": "esbuild --format=esm src/**/*.ts --outdir=dist && nodemon --env-file=.env.staging dist/app.js", "build:prod": "esbuild src/*.ts --bundle --platform=node --outdir=dist --external:@aws-sdk && cd dist && zip -r lambda.zip * > /dev/null && aws --profile equalify lambda update-function-code --function-name equalify-api --zip-file \"fileb://lambda.zip\" > /dev/null && rm -rf lambda.zip", - "build:staging": "esbuild src/*.ts --bundle --platform=node --outdir=dist --external:@aws-sdk && cd dist && zip -r lambda.zip * > /dev/null && aws --profile equalify lambda update-function-code --function-name equalify-api-staging --zip-file \"fileb://lambda.zip\" > /dev/null && rm -rf lambda.zip" + "build:staging": "esbuild src/*.ts --bundle --platform=node --outdir=dist --external:@aws-sdk && cd dist && zip -r lambda.zip * > /dev/null && aws --profile equalify lambda update-function-code --function-name equalify-api-staging --zip-file \"fileb://lambda.zip\" > /dev/null && rm -rf lambda.zip", + "build": "yarn build:staging && yarn build:prod" }, "type": "module", "dependencies": {}, diff --git a/src/cognito.ts b/src/cognito.ts new file mode 100644 index 0000000..4b6533e --- /dev/null +++ b/src/cognito.ts @@ -0,0 +1,28 @@ +import { postConfirmationConfirmSignUp, postConfirmationConfirmForgotPassword, customMessageSignUp, customMessageResendCode, customMessageForgotPassword, customMessageVerifyUserAttribute, customMessageUpdateUserAttribute } from 'cognito/index.js'; + +export const cognito = async (event) => { + if (event.triggerSource === 'PostConfirmation_ConfirmSignUp') { + return postConfirmationConfirmSignUp(event); + } + else if (event.triggerSource === 'PostConfirmation_ConfirmForgotPassword') { + return postConfirmationConfirmForgotPassword(event); + } + else if (event.triggerSource === 'CustomMessage_SignUp') { + return customMessageSignUp(event); + } + else if (event.triggerSource === 'CustomMessage_ResendCode') { + return customMessageResendCode(event); + } + else if (event.triggerSource === 'CustomMessage_ForgotPassword') { + return customMessageForgotPassword(event); + } + else if (event.triggerSource === 'CustomMessage_VerifyUserAttribute') { + return customMessageVerifyUserAttribute(event); + } + else if (event.triggerSource === 'CustomMessage_UpdateUserAttribute') { + return customMessageUpdateUserAttribute(event); + } + else { + return event; + } +} diff --git a/src/cognito/customMessageForgotPassword.ts b/src/cognito/customMessageForgotPassword.ts new file mode 100644 index 0000000..0a4e396 --- /dev/null +++ b/src/cognito/customMessageForgotPassword.ts @@ -0,0 +1,7 @@ +import { formatEmail } from "../utils"; + +export const customMessageForgotPassword = async (event) => { + event.response.emailSubject = `Please reset your password`; + event.response.emailMessage = formatEmail({ body: `

${event.request.userAttributes['name']},

Please reset your password by clicking here.

Thank you,
Equalify

${event.request.codeParameter}${event.request.codeParameter}
` }); + return event; +} \ No newline at end of file diff --git a/src/cognito/customMessageResendCode.ts b/src/cognito/customMessageResendCode.ts new file mode 100644 index 0000000..e34f380 --- /dev/null +++ b/src/cognito/customMessageResendCode.ts @@ -0,0 +1,7 @@ +import { formatEmail } from "../utils"; + +export const customMessageResendCode = async (event) => { + event.response.emailSubject = `Confirm your registration to Equalify`; + event.response.emailMessage = formatEmail({ body: `

${event.request.userAttributes['name']},

Please confirm your registration by clicking here.

Thank you,
Equalify

${event.request.codeParameter}${event.request.codeParameter}
` }); + return event; +} \ No newline at end of file diff --git a/src/cognito/customMessageSignUp.ts b/src/cognito/customMessageSignUp.ts new file mode 100644 index 0000000..b57ca2b --- /dev/null +++ b/src/cognito/customMessageSignUp.ts @@ -0,0 +1,3 @@ +export const customMessageSignUp = async (event) => { + return event; +} \ No newline at end of file diff --git a/src/cognito/customMessageUpdateUserAttribute.ts b/src/cognito/customMessageUpdateUserAttribute.ts new file mode 100644 index 0000000..a238f3f --- /dev/null +++ b/src/cognito/customMessageUpdateUserAttribute.ts @@ -0,0 +1,8 @@ +import { formatEmail } from "../utils"; + +export const customMessageUpdateUserAttribute = async (event) => { + event.response.emailSubject = `Please confirm your new email address`; + event.response.emailMessage = formatEmail({ body: `

${event.request.userAttributes['name']},

Please confirm your new email address by clicking here.

Thank you,
Equalify

${event.request.codeParameter}${event.request.codeParameter}
` }); + + return event; +} \ No newline at end of file diff --git a/src/cognito/customMessageVerifyUserAttribute.ts b/src/cognito/customMessageVerifyUserAttribute.ts new file mode 100644 index 0000000..1c4bf42 --- /dev/null +++ b/src/cognito/customMessageVerifyUserAttribute.ts @@ -0,0 +1,5 @@ +export const customMessageVerifyUserAttribute = async (event) => { + event.response.smsMessage = `Equalify: Verify your phone number by visting "https://${process.env.STAGING ? 'staging.' : ''}equalify.dev/verify?type=phone_number&code=${event.request.codeParameter}"`; + + return event; +} \ No newline at end of file diff --git a/src/cognito/index.ts b/src/cognito/index.ts new file mode 100644 index 0000000..9b6e1b9 --- /dev/null +++ b/src/cognito/index.ts @@ -0,0 +1,7 @@ +export * from './postConfirmationConfirmSignUp.js' +export * from './postConfirmationConfirmForgotPassword.js' +export * from './customMessageSignUp.js' +export * from './customMessageVerifyUserAttribute.js' +export * from './customMessageUpdateUserAttribute.js' +export * from './customMessageResendCode.js' +export * from './customMessageForgotPassword.js' \ No newline at end of file diff --git a/src/cognito/postConfirmationConfirmForgotPassword.ts b/src/cognito/postConfirmationConfirmForgotPassword.ts new file mode 100644 index 0000000..e543637 --- /dev/null +++ b/src/cognito/postConfirmationConfirmForgotPassword.ts @@ -0,0 +1,3 @@ +export const postConfirmationConfirmForgotPassword = async (event) => { + return event; +} \ No newline at end of file diff --git a/src/cognito/postConfirmationConfirmSignUp.ts b/src/cognito/postConfirmationConfirmSignUp.ts new file mode 100644 index 0000000..0e948c0 --- /dev/null +++ b/src/cognito/postConfirmationConfirmSignUp.ts @@ -0,0 +1,11 @@ +import { pgClient } from "../utils/index.js"; + +export const postConfirmationConfirmSignUp = async (event) => { + const { sub, email, name } = event.request.userAttributes; + await pgClient.connect(); + await pgClient.query(` + INSERT INTO "users" ("id", "email", "name") VALUES ($1, $2, $3) + `, [sub, email, name]); + await pgClient.clean(); + return event; +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 6834e67..aa18840 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,11 @@ import awsLambdaFastify from "@fastify/aws-lambda"; import { fastify } from "./app.js"; +import { cognito } from './cognito.js'; const proxy = awsLambdaFastify(fastify); export async function handler(event: any, context: any) { + if (event.triggerSource) { + return await cognito(event); + } return await proxy(event, context); } \ No newline at end of file diff --git a/src/routes/getReports.ts b/src/routes/getReports.ts index 1787591..4472877 100644 --- a/src/routes/getReports.ts +++ b/src/routes/getReports.ts @@ -4,9 +4,9 @@ export const getReports = async ({ request, reply }) => { const response = (await graphqlQuery({ query: `query($first: Int, $offset: Int){ reports(first: $first, offset: $offset, ${(request.query.reportIds) ? `filter: { id: {in: [ - ${request.query.reportIds.split(',').map(obj => `"${obj}"`).join()} - ]}}` : ''} - ) { + ${request.query.reportIds.split(',').map(obj => `"${obj}"`).join()} + ]}}` : ''} + ) { nodes { id name diff --git a/src/routes/getScans.ts b/src/routes/getScans.ts index 8da9ebd..c61be80 100644 --- a/src/routes/getScans.ts +++ b/src/routes/getScans.ts @@ -1,8 +1,27 @@ -import { jwtClaims } from '../app.js'; -import { pgClient } from '../utils/index.js'; +import { graphqlQuery } from '../utils/index.js'; export const getScans = async ({ request, reply }) => { - await pgClient.connect(); - await pgClient.clean(); - return; + const response = (await graphqlQuery({ + query: `query($first: Int, $offset: Int){ + scans(first: $first, offset: $offset, ${(request.query.scanIds) ? `filter: { id: {in: [ + ${request.query.scanIds.split(',').map(obj => `"${obj}"`).join()} + ]}}` : ''} + ) { + nodes { + id + } + totalCount + } + }`, + variables: { + first: parseInt(request.query.first ?? 100), + offset: parseInt(request.query.offset ?? 0), + }, + }))?.data; + + return { + status: 'success', + result: response?.scans?.nodes, + total: response?.scans?.totalCount, + }; } \ No newline at end of file diff --git a/src/routes/getUpdates.ts b/src/routes/getUpdates.ts index 6205198..d0c829a 100644 --- a/src/routes/getUpdates.ts +++ b/src/routes/getUpdates.ts @@ -1,8 +1,29 @@ -import { jwtClaims } from '../app.js'; -import { pgClient } from '../utils/index.js'; +import { graphqlQuery } from '../utils/index.js'; export const getUpdates = async ({ request, reply }) => { - await pgClient.connect(); - await pgClient.clean(); - return; + const response = (await graphqlQuery({ + query: `query($first: Int, $offset: Int){ + updates(first: $first, offset: $offset, ${(request.query.startDate && request.query.endDate) ? `filter: { + created_at: { greaterThan: "${request.query.startDate}" }, + created_at: { lessThan: "${request.query.endDate}" } + }` : ''} + ) { + nodes { + id + created_at + } + totalCount + } + }`, + variables: { + first: parseInt(request.query.first ?? 100), + offset: parseInt(request.query.offset ?? 0), + }, + }))?.data; + + return { + status: 'success', + result: response?.updates?.nodes, + total: response?.updates?.totalCount, + }; } \ No newline at end of file diff --git a/src/utils/formatEmail.ts b/src/utils/formatEmail.ts new file mode 100644 index 0000000..415e87c --- /dev/null +++ b/src/utils/formatEmail.ts @@ -0,0 +1,3 @@ +export const formatEmail = ({ body }) => { + return `

${body}`; +}; diff --git a/src/utils/index.ts b/src/utils/index.ts index f21c078..55e7fe1 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -4,4 +4,5 @@ export * from './openai.js' export * from './validateUuid.js' export * from './validateUrl.js' export * from './validateDiscovery.js' -export * from './formatId.js' \ No newline at end of file +export * from './formatId.js' +export * from './formatEmail.js' \ No newline at end of file