Skip to content

Commit

Permalink
upgrading NodeJS runtime to 20.x
Browse files Browse the repository at this point in the history
  • Loading branch information
danielpastor97 committed Sep 3, 2024
1 parent df3bb43 commit a5b7c75
Show file tree
Hide file tree
Showing 11 changed files with 4,488 additions and 1,099 deletions.
36 changes: 26 additions & 10 deletions docs/announcements/backend/lambda/sendAnnouncement.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const ses = new AWS.SES();
// AWS SDK v3 imports
const { S3Client, GetObjectCommand } = require("@aws-sdk/client-s3");
const { DynamoDBClient, ScanCommand } = require("@aws-sdk/client-dynamodb");
const { SESClient, SendEmailCommand } = require("@aws-sdk/client-ses");
const { stringify } = require("querystring");

// Initialize AWS SDK v3 clients
const s3 = new S3Client({});
const dynamoDb = new DynamoDBClient({});
const ses = new SESClient({});

exports.handler = async (event) => {
const bucketName = process.env.BUCKET_NAME;
Expand All @@ -16,17 +22,17 @@ exports.handler = async (event) => {
};

try {
const data = await s3.getObject(params).promise();
const announcementContent = data.Body.toString('utf-8');
const data = await s3.send(new GetObjectCommand(params));
const announcementContent = (await streamToString(data.Body)).toString('utf-8');

// Extract the title and content without front matter from the markdown file
const { title, description } = extractTitleAndContent(announcementContent);

const subscribers = await dynamoDb.scan({ TableName: tableName }).promise();
const subscribers = await dynamoDb.send(new ScanCommand({ TableName: tableName }));
const emailPromises = subscribers.Items.map(item => {
const emailParams = {
Source: '[email protected]',
Destination: { ToAddresses: [item.email] },
Destination: { ToAddresses: [`${item.email.S}`] },
Message: {
Subject: { Data: `New Announcement from the Martini Force Field Initiative.` },
Body: { Html: { Data:
Expand All @@ -43,7 +49,7 @@ exports.handler = async (event) => {
<br><br>
<hr style="border: 0.5px solid #000;">
<em>If you no longer wish to receive emails from us, you can <a href="https://q8hgi2weih.execute-api.ca-central-1.amazonaws.com/prod/unsubscribe?email=${encodeURIComponent(item.email)}&token=${item.token}">unsubscribe from our mailing list</a>.</em>
<em>If you no longer wish to receive emails from us, you can <a href="https://q8hgi2weih.execute-api.ca-central-1.amazonaws.com/prod/unsubscribe?email=${encodeURIComponent(item.email.S)}&token=${item.token.S}">unsubscribe from our mailing list</a>.</em>
<hr style="border: 0.5px solid #000;">
Expand All @@ -52,7 +58,7 @@ exports.handler = async (event) => {
} },
},
};
return ses.sendEmail(emailParams).promise();
return ses.send(new SendEmailCommand(emailParams));
});

await Promise.all(emailPromises);
Expand All @@ -63,6 +69,16 @@ exports.handler = async (event) => {
}
};

// Utility function to convert stream to string
const streamToString = async (stream) => {
const chunks = [];
for await (const chunk of stream) {
chunks.push(chunk);
}
return Buffer.concat(chunks);
};

// function to extract title and content from markdown content
function extractTitleAndContent(markdownContent) {
const frontMatterMatch = markdownContent.match(/---([\s\S]*?)---/);
if (!frontMatterMatch) {
Expand Down
27 changes: 16 additions & 11 deletions docs/announcements/backend/lambda/subscribe.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient();
const ses = new AWS.SES();
const crypto = require('crypto');
// AWS SDK v3 specific requires
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { GetCommand, PutCommand } = require("@aws-sdk/lib-dynamodb");
const { SESClient, SendEmailCommand } = require("@aws-sdk/client-ses");
const crypto = require("crypto");

// Initialize AWS SDK v3 clients
const dynamoDb = new DynamoDBClient({});
const ses = new SESClient({});

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const verificationTable = process.env.VERIFICATION_TABLE_NAME;
Expand All @@ -22,13 +27,13 @@ exports.handler = async (event) => {

try {
// Check if the email is already subscribed
const params = {
const getParams = {
TableName: process.env.TABLE_NAME,
Key: { email },
};
const result = await dynamoDb.get(params).promise();
const getResult = await dynamoDb.send(new GetCommand(getParams));

if (result.Item) {
if (getResult.Item) {
return {
statusCode: 200,
body: JSON.stringify({ message: 'Email already subscribed' }),
Expand All @@ -43,7 +48,7 @@ exports.handler = async (event) => {
TableName: verificationTable,
Item: { email, token, verified: false },
};
await dynamoDb.put(verificationParams).promise();
await dynamoDb.send(new PutCommand(verificationParams));

// Send a verification email
const verificationUrl = `${baseUrl}/verifyEmail?token=${token}&email=${encodeURIComponent(email)}`;
Expand All @@ -55,7 +60,7 @@ exports.handler = async (event) => {
Body: {
Html: {
Data: `
Please verify your email by clicking the following link: <a href=${verificationUrl}>${verificationUrl}</a>. <br><br>
Please verify your email by clicking the following link: <a href="${verificationUrl}">${verificationUrl}</a>. <br><br>
<em>Note: If you did not submit a subscription request to the Martini Force Field Initiative, please ignore this email.</em>
`,
Expand All @@ -67,7 +72,7 @@ exports.handler = async (event) => {
},
Source: process.env.SOURCE_EMAIL,
};
await ses.sendEmail(emailParams).promise();
await ses.send(new SendEmailCommand(emailParams));

return {
statusCode: 200,
Expand All @@ -77,7 +82,7 @@ exports.handler = async (event) => {
console.error("Error:", error);
return {
statusCode: 500,
body: JSON.stringify({ message: 'An error occurred', error }),
body: JSON.stringify({ message: 'An error occurred', error: error.message }),
};
}
};
28 changes: 18 additions & 10 deletions docs/announcements/backend/lambda/unsubscribe.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient();
// AWS SDK v3 specific requires
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { GetCommand, DeleteCommand } = require("@aws-sdk/lib-dynamodb");

// Initialize AWS SDK v3 client
const dynamoDb = new DynamoDBClient({});

exports.handler = async (event) => {
const email = event.queryStringParameters.email;
Expand All @@ -16,17 +20,20 @@ exports.handler = async (event) => {
};

try {
const data = await dynamoDb.get(params).promise();
// Check the email token
const data = await dynamoDb.send(new GetCommand(params));

if (data.Item && data.Item.token === token) {
await dynamoDb.delete(params).promise();
await dynamoDb.delete(params_verify).promise();
// Delete from both tables
await dynamoDb.send(new DeleteCommand(params));
await dynamoDb.send(new DeleteCommand(params_verify));

return {
statusCode: 200,
headers: {
'Content-Type': 'text/html',
},
body: `
},
body: `
<!DOCTYPE html>
<html lang="en">
<head>
Expand Down Expand Up @@ -88,18 +95,19 @@ exports.handler = async (event) => {
</div>
</body>
</html>
`,
};
`,
};
} else {
return {
statusCode: 400,
body: JSON.stringify({ message: 'Invalid token' }),
};
}
} catch (error) {
console.error("Error:", error);
return {
statusCode: 500,
body: JSON.stringify({ message: 'An error occurred' }),
body: JSON.stringify({ message: 'An error occurred', error: error.message }),
};
}
};
22 changes: 13 additions & 9 deletions docs/announcements/backend/lambda/verifyEmail.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient();
// AWS SDK v3 specific requires
const { DynamoDBClient } = require("@aws-sdk/client-dynamodb");
const { GetCommand, UpdateCommand, PutCommand } = require("@aws-sdk/lib-dynamodb");

// Initialize AWS SDK v3 client
const dynamoDb = new DynamoDBClient({});

const verificationTable = process.env.VERIFICATION_TABLE_NAME;
const subscribeTable = process.env.TABLE_NAME;
Expand All @@ -15,19 +19,19 @@ exports.handler = async (event) => {
if (!token || !email) {
return {
statusCode: 400,
body: JSON.stringify({ message: token }),
body: JSON.stringify({ message: 'Missing token or email' }),
};
}

try {
// Check the verification token
const params = {
const getParams = {
TableName: verificationTable,
Key: { email },
};
const result = await dynamoDb.get(params).promise();
const getResult = await dynamoDb.send(new GetCommand(getParams));

if (!result.Item || result.Item.token !== token) {
if (!getResult.Item || getResult.Item.token !== token) {
return {
statusCode: 400,
body: JSON.stringify({ message: 'Invalid token' }),
Expand All @@ -43,7 +47,7 @@ exports.handler = async (event) => {
':verified': true,
},
};
await dynamoDb.update(updateParams).promise();
await dynamoDb.send(new UpdateCommand(updateParams));

// Move the email to the subscribed table
const subscribeParams = {
Expand All @@ -53,7 +57,7 @@ exports.handler = async (event) => {
token: token,
},
};
await dynamoDb.put(subscribeParams).promise();
await dynamoDb.send(new PutCommand(subscribeParams));

return {
statusCode: 200,
Expand Down Expand Up @@ -127,7 +131,7 @@ exports.handler = async (event) => {
console.error("Error:", error);
return {
statusCode: 500,
body: JSON.stringify({ message: 'An error occurred', error }),
body: JSON.stringify({ message: 'An error occurred', error: error.message }),
};
}
};
9 changes: 4 additions & 5 deletions docs/announcements/backend/lib/backend-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as s3n from 'aws-cdk-lib/aws-s3-notifications';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as ses from 'aws-cdk-lib/aws-ses';

export class AnnouncementsStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
Expand All @@ -29,7 +28,7 @@ export class AnnouncementsStack extends cdk.Stack {

// Create Lambda functions
const subscribeFunction = new lambda.Function(this, 'SubscribeFunction', {
runtime: lambda.Runtime.NODEJS_18_X,
runtime: lambda.Runtime.NODEJS_20_X,
code: lambda.Code.fromAsset('lambda'),
handler: 'subscribe.handler',
environment: {
Expand All @@ -42,7 +41,7 @@ export class AnnouncementsStack extends cdk.Stack {

// Create a Lambda function for verifying email addresses
const verifyEmailFunction = new lambda.Function(this, 'VerifyEmailFunction', {
runtime: lambda.Runtime.NODEJS_18_X,
runtime: lambda.Runtime.NODEJS_20_X,
code: lambda.Code.fromAsset('lambda'),
handler: 'verifyEmail.handler',
environment: {
Expand All @@ -53,7 +52,7 @@ export class AnnouncementsStack extends cdk.Stack {

// Create a Lambda function for unsubscribing
const unsubscribeFunction = new lambda.Function(this, 'UnsubscribeFunction', {
runtime: lambda.Runtime.NODEJS_18_X,
runtime: lambda.Runtime.NODEJS_20_X,
code: lambda.Code.fromAsset('lambda'),
handler: 'unsubscribe.handler',
environment: {
Expand All @@ -64,7 +63,7 @@ export class AnnouncementsStack extends cdk.Stack {

// Create a Lambda function for sending announcement emails
const sendAnnouncementFunction = new lambda.Function(this, 'SendAnnouncementFunction', {
runtime: lambda.Runtime.NODEJS_18_X,
runtime: lambda.Runtime.NODEJS_20_X,
code: lambda.Code.fromAsset('lambda'),
handler: 'sendAnnouncement.handler',
environment: {
Expand Down
Loading

0 comments on commit a5b7c75

Please sign in to comment.