Skip to content

Commit

Permalink
defined sendEmailNotification in lambda + more async-labs#18
Browse files Browse the repository at this point in the history
  • Loading branch information
tima101 committed Apr 25, 2019
1 parent 1ef1e2a commit 91395d7
Show file tree
Hide file tree
Showing 8 changed files with 1,248 additions and 578 deletions.
1 change: 0 additions & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
"express-session": "1.15.6",
"front-matter": "3.0.1",
"googleapis": "38.0.0",
"handlebars": "4.1.1",
"he": "1.2.0",
"helmet": "3.16.0",
"highlight.js": "9.15.6",
Expand Down
52 changes: 39 additions & 13 deletions api/server/models/EmailTemplate.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Handlebars from 'handlebars';
import * as _ from 'lodash';
import * as mongoose from 'mongoose';

interface IEmailTemplateDocument extends mongoose.Document {
Expand Down Expand Up @@ -31,7 +31,7 @@ async function insertTemplates() {
{
name: 'welcome',
subject: 'Welcome to SaaS by Async',
message: `{{userName}},
message: `<%= userName %>,
<p>
Thanks for signing up on our <a href="https://github.com/async-labs/saas" target="blank">SaaS boilerplate</a>!
<br/>
Expand All @@ -55,31 +55,57 @@ async function insertTemplates() {
{
name: 'invitation',
subject: 'You are invited to join a Team at async-await.com',
message: `You've been invited to join <b>{{teamName}}</b>.
<br/>Click here to accept the invitation: {{invitationURL}}
message: `You've been invited to join <b><%= teamName%></b>.
<br/>Click here to accept the invitation: <%= invitationURL%>
`,
},
{
name: 'newPost',
subject: 'New Post was created in Discussion: <%= discussionName %>',
message: `<p>New Post in Discussion: "<%= discussionName%>" by <%= authorName%></p>
New Post: "<%= postContent %>"
<p>---</p>
<p>View it at <a href="<%= discussionLink %>"><%= discussionLink %></a>.</p>
`,
},
];

for (const t of templates) {
if ((await EmailTemplate.countDocuments({ name: t.name })) === 0) {
EmailTemplate.create(
Object.assign({}, t, { message: t.message.replace(/\n/g, '').replace(/[ ]+/g, ' ') }),
);
const et = await EmailTemplate.findOne({ name: t.name });
const message = t.message
.replace(/\n/g, '')
.replace(/[ ]+/g, ' ')
.trim();

if (!et) {
EmailTemplate.create(Object.assign({}, t, { message }));
} else if (et.subject !== t.subject || et.message !== message) {
EmailTemplate.updateOne({ _id: et._id }, { $set: { message, subject: t.subject } }).exec();
}
}
}

insertTemplates();

export default async function getEmailTemplate(name, params) {
const source = await EmailTemplate.findOne({ name });
export default async function getEmailTemplate(
name: string,
params: any,
template?: IEmailTemplateDocument,
) {
const source =
template ||
(await EmailTemplate.findOne({ name }).setOptions({
lean: true,
}));

if (!source) {
throw new Error('not found');
throw new Error('Email Template is not found.');
}

return {
message: Handlebars.compile(source.message)(params),
subject: Handlebars.compile(source.subject)(params),
message: _.template(source.message)(params),
subject: _.template(source.subject)(params),
};
}

export { EmailTemplate, IEmailTemplateDocument };
20 changes: 16 additions & 4 deletions api/server/models/Invitation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as mongoose from 'mongoose';

import sendEmail from '../aws-ses';
import logger from '../logs';
import getEmailTemplate from './EmailTemplate';
import getEmailTemplate, { EmailTemplate } from './EmailTemplate';
import Team from './Team';
import User, { IUserDocument } from './User';

Expand Down Expand Up @@ -121,11 +121,23 @@ class InvitationClass extends mongoose.Model {
});
}

const template = await getEmailTemplate('invitation', {
teamName: team.name,
invitationURL: `${ROOT_URL}/invitation?token=${token}`,
const emailTemplate = await EmailTemplate.findOne({ name: 'invitation' }).setOptions({
lean: true,
});

if (!emailTemplate) {
throw new Error('invitation Email template not found');
}

const template = await getEmailTemplate(
'invitation',
{
teamName: team.name,
invitationURL: `${ROOT_URL}/invitation?token=${token}`,
},
emailTemplate,
);

await sendEmail({
from: `Kelly from async-await.com <${process.env.EMAIL_SUPPORT_FROM_ADDRESS}>`,
to: [email],
Expand Down
3 changes: 2 additions & 1 deletion app/components/teams/InviteMember.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@ class InviteMember extends React.Component<Props, State> {
<DialogTitle id="invite-memter-dialog-title">Invite member</DialogTitle>
<form onSubmit={this.onSubmit} style={{ padding: '20px' }}>
<TextField
autoFocus
autoComplete="off"
value={this.state.email}
placeholder="Email"
onChange={event => {
this.setState({ email: event.target.value });
}}
/>
<p />
<br />
<Button variant="outlined" onClick={this.handleClose} disabled={this.state.disabled}>
Cancel
</Button>{' '}
Expand Down
10 changes: 9 additions & 1 deletion lambda/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,16 @@ export const sendEmailForNewPost = async event => {

await mongoose.connect(MONGO_URL, { useNewUrlParser: true, useFindAndModify: false });

const { discussionName, postContent, authorName, userIds } = event;

try {
await sendEmailNotification(process.env.PRODUCTION_URL_APP);
await sendEmailNotification({
productionUrlApp: process.env.PRODUCTION_URL_APP,
discussionName,
postContent,
authorName,
userIds,
});
} catch (error) {
console.error(error.stack);

Expand Down
36 changes: 18 additions & 18 deletions lambda/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,36 @@
"lint": "tslint '*.ts'"
},
"devDependencies": {
"@types/lodash": "^4.14.117",
"@types/mongoose": "^5.2.20",
"@types/node": "^10.12.0",
"aws-sdk": "^2.344.0",
"@types/lodash": "^4.14.123",
"@types/mongoose": "^5.3.26",
"@types/node": "^11.13.7",
"aws-sdk": "^2.443.0",
"serverless-dotenv-plugin": "^2.0.1",
"serverless-plugin-typescript": "^1.1.5",
"ts-node": "^7.0.1",
"tslint": "^5.11.0",
"typescript": "^3.1.3"
"serverless-plugin-typescript": "^1.1.7",
"ts-node": "^8.1.0",
"tslint": "^5.16.0",
"typescript": "^3.4.5"
},
"dependencies": {
"@octokit/rest": "^16.2.0",
"@octokit/rest": "^16.25.0",
"body-parser": "^1.18.3",
"chart.js": "^2.7.3",
"chart.js": "^2.8.0",
"chartjs-node": "^1.7.1",
"chartjs-plugin-datalabels": "^0.5.0",
"chartjs-plugin-datalabels": "^0.6.0",
"email-addresses": "^3.0.3",
"express": "^4.16.4",
"he": "^1.2.0",
"highlight.js": "^9.13.1",
"highlight.js": "^9.15.6",
"lodash": "^4.17.11",
"mailparser": "^2.6.0",
"marked": "^0.5.1",
"moment": "^2.22.2",
"mongoose": "^5.3.7",
"marked": "^0.6.2",
"moment": "^2.24.0",
"mongoose": "^5.5.4",
"passport": "^0.4.0",
"passport-github": "^1.1.0",
"request": "^2.88.0",
"socket.io": "^2.1.1",
"stripe": "^6.12.1",
"winston": "^3.1.0"
"socket.io": "^2.2.0",
"stripe": "^6.31.0",
"winston": "^3.2.1"
}
}
80 changes: 66 additions & 14 deletions lambda/src/sendEmailForNewPost.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,71 @@
// import * as _ from 'lodash';
import * as _ from 'lodash';
// import * as moment from 'moment';

// import sendEmail from './api/aws-ses';
// import getEmailTemplate, {
// EmailTemplate,
// IEmailTemplateDocument,
// } from './api/models/EmailTemplate';
// import User, { IUserDocument } from './api/models/User';

async function sendEmailNotification(productionUrlApp: string) {
console.log(productionUrlApp);
// pass more arguments
// get email template for new post
// find users
// send email with passed data to each user with sendEmail()
import sendEmail from './api/aws-ses';
import getEmailTemplate, { EmailTemplate } from './api/models/EmailTemplate';
import User from './api/models/User';

// interface IUserDocumentWithId extends IUserDocument {
// _id: string;
// }

async function sendEmailNotification({
productionUrlApp,
discussionName,
postContent,
authorName,
userIds,
}: {
productionUrlApp: string;
discussionName: string;
postContent: string;
authorName: string;
userIds: string[];
}) {
console.log(productionUrlApp, discussionName, postContent, authorName, userIds);

const emailTemplate = await EmailTemplate.findOne({ name: 'newPost' }).setOptions({
lean: true,
});

if (!emailTemplate) {
throw new Error('newPost Email template not found');
}

const templateWithData = await getEmailTemplate(
'newPost',
{
discussionName,
postContent,
authorName,
},
emailTemplate,
);

const users = await User.find()
.select('email')
.setOptions({ lean: true });

const usersToNotify = users.filter(user => userIds.includes(user._id));

const jobs = _.flatten(
usersToNotify
.filter(user => !!user.email)
.map(async user => {
try {
await sendEmail({
from: `From async-await.com <${process.env.EMAIL_SUPPORT_FROM_ADDRESS}>`,
to: [user.email],
subject: templateWithData.subject,
body: templateWithData.message,
});
} catch (err) {
console.error(err.stack);
}
}),
);

await Promise.all(jobs);
}

export { sendEmailNotification };
Loading

0 comments on commit 91395d7

Please sign in to comment.