From c9896ad4bfa36057191a8442fd670a1566c282a5 Mon Sep 17 00:00:00 2001 From: Buyantogtokh Date: Sun, 1 Dec 2019 22:29:36 +0800 Subject: [PATCH] feat(user): now users can unsubscribe from notification emails close #655, close #654 --- src/data/resolvers/mutations/engageUtils.ts | 6 -- src/data/schema/user.ts | 1 + src/data/utils.ts | 64 ++++++++++++++++---- src/db/models/definitions/users.ts | 1 + src/index.ts | 14 +++-- src/private/emailTemplates/notification.html | 3 +- 6 files changed, 67 insertions(+), 22 deletions(-) diff --git a/src/data/resolvers/mutations/engageUtils.ts b/src/data/resolvers/mutations/engageUtils.ts index 625f3e0fd..315127015 100644 --- a/src/data/resolvers/mutations/engageUtils.ts +++ b/src/data/resolvers/mutations/engageUtils.ts @@ -209,9 +209,3 @@ export const sendViaMessenger = async ( }); } }; - -/* - * Handle engage unsubscribe request - */ -export const handleEngageUnSubscribe = (query: { cid: string }) => - Customers.updateOne({ _id: query.cid }, { $set: { doNotDisturb: 'Yes' } }); diff --git a/src/data/schema/user.ts b/src/data/schema/user.ts index 93e5fa8c3..2ff6be0c9 100644 --- a/src/data/schema/user.ts +++ b/src/data/schema/user.ts @@ -58,6 +58,7 @@ export const types = ` getNotificationByEmail: Boolean groupIds: [String] brandIds: [String] + doNotDisturb: String brands: [Brand] isOwner: Boolean diff --git a/src/data/utils.ts b/src/data/utils.ts index 274e602dc..9cecf5121 100644 --- a/src/data/utils.ts +++ b/src/data/utils.ts @@ -320,20 +320,23 @@ export const createTransporter = ({ ses }) => { * Send email */ export const sendEmail = async ({ - toEmails, + toEmails = [], fromEmail, title, template = {}, + modifier, }: { toEmails?: string[]; fromEmail?: string; title?: string; template?: { name?: string; data?: any; isCustom?: boolean }; + modifier?: (data: any, email: string) => void; }) => { const NODE_ENV = getEnv({ name: 'NODE_ENV' }); const DEFAULT_EMAIL_SERVICE = getEnv({ name: 'DEFAULT_EMAIL_SERVICE', defaultValue: '' }) || 'SES'; const COMPANY_EMAIL_FROM = getEnv({ name: 'COMPANY_EMAIL_FROM' }); const AWS_SES_CONFIG_SET = getEnv({ name: 'AWS_SES_CONFIG_SET', defaultValue: '' }); + const DOMAIN = getEnv({ name: 'DOMAIN' }); // do not send email it is running in test mode if (NODE_ENV === 'test') { @@ -351,14 +354,21 @@ export const sendEmail = async ({ const { isCustom, data, name } = template; - // generate email content by given template - let html = await applyTemplate(data, name || ''); + // for unsubscribe url + data.domain = DOMAIN; - if (!isCustom) { - html = await applyTemplate({ content: html }, 'base'); - } + for (const toEmail of toEmails) { + if (modifier) { + modifier(data, toEmail); + } + + // generate email content by given template + let html = await applyTemplate(data, name || ''); + + if (!isCustom) { + html = await applyTemplate({ content: html }, 'base'); + } - return (toEmails || []).map(toEmail => { const mailOptions = { from: fromEmail || COMPANY_EMAIL_FROM, to: toEmail, @@ -373,7 +383,7 @@ export const sendEmail = async ({ debugEmail(error); debugEmail(info); }); - }); + } }; /** @@ -406,7 +416,7 @@ export const sendNotification = async (doc: ISendNotification) => { const receiverIds = [...new Set(receivers)]; // collecting emails - const recipients = await Users.find({ _id: { $in: receiverIds } }); + const recipients = await Users.find({ _id: { $in: receiverIds }, isActive: true, doNotDisturb: { $ne: 'Yes' } }); // collect recipient emails const toEmails: string[] = []; @@ -439,12 +449,21 @@ export const sendNotification = async (doc: ISendNotification) => { throw e; } } - } + } // end receiverIds loop const MAIN_APP_DOMAIN = getEnv({ name: 'MAIN_APP_DOMAIN' }); link = `${MAIN_APP_DOMAIN}${link}`; + // for controlling email template data filling + const modifier = (data: any, email: string) => { + const user = recipients.find(item => item.email === email); + + if (user) { + data.uid = user._id; + } + }; + await sendEmail({ toEmails, title: 'Notification', @@ -456,6 +475,7 @@ export const sendNotification = async (doc: ISendNotification) => { userName: getUserDetail(createdUser), }, }, + modifier, }); return true; @@ -806,8 +826,13 @@ export const getToday = (date: Date): Date => { export const getNextMonth = (date: Date): { start: number; end: number } => { const today = getToday(date); + const currentMonth = new Date().getMonth(); - const month = (new Date().getMonth() + 1) % 12; + if (currentMonth === 11) { + today.setFullYear(today.getFullYear() + 1); + } + + const month = (currentMonth + 1) % 12; const start = today.setMonth(month, 1); const end = today.setMonth(month + 1, 0); @@ -856,3 +881,20 @@ export const regexSearchText = (searchValue: string) => { return { $and: result }; }; + +/* + * Handle engage unsubscribe request + */ +export const handleUnsubscription = async (query: { cid: string; uid: string }) => { + const { cid, uid } = query; + + if (cid) { + await Customers.updateOne({ _id: cid }, { $set: { doNotDisturb: 'Yes' } }); + } + + if (uid) { + await Users.updateOne({ _id: uid }, { $set: { doNotDisturb: 'Yes' } }); + } + + return true; +}; diff --git a/src/db/models/definitions/users.ts b/src/db/models/definitions/users.ts index 0e91d9e87..2dcf65e3b 100644 --- a/src/db/models/definitions/users.ts +++ b/src/db/models/definitions/users.ts @@ -115,4 +115,5 @@ export const userSchema = new Schema({ brandIds: field({ type: [String] }), groupIds: field({ type: [String] }), deviceTokens: field({ type: [String], default: [] }), + doNotDisturb: field({ type: String, optional: true, default: 'No', label: 'Do not disturb' }), }); diff --git a/src/index.ts b/src/index.ts index a5de22f16..8d2df2c1d 100755 --- a/src/index.ts +++ b/src/index.ts @@ -13,8 +13,14 @@ import { filterXSS } from 'xss'; import apolloServer from './apolloClient'; import { companiesExport, customersExport } from './data/modules/coc/exporter'; import insightExports from './data/modules/insights/insightExports'; -import { handleEngageUnSubscribe } from './data/resolvers/mutations/engageUtils'; -import { checkFile, getEnv, readFileRequest, registerOnboardHistory, uploadFile } from './data/utils'; +import { + checkFile, + getEnv, + handleUnsubscription, + readFileRequest, + registerOnboardHistory, + uploadFile, +} from './data/utils'; import { connect } from './db/connection'; import { debugExternalApi, debugInit } from './debuggers'; import './messageBroker'; @@ -241,8 +247,8 @@ app.post('/import-file', async (req: any, res, next) => { }); // engage unsubscribe -app.get('/unsubscribe', async (req, res) => { - const unsubscribed = await handleEngageUnSubscribe(req.query); +app.get('/unsubscribe', async (req: any, res) => { + const unsubscribed = await handleUnsubscription(req.query); if (unsubscribed) { res.setHeader('Content-Type', 'text/html; charset=utf-8'); diff --git a/src/private/emailTemplates/notification.html b/src/private/emailTemplates/notification.html index 37c080253..ef4935f38 100644 --- a/src/private/emailTemplates/notification.html +++ b/src/private/emailTemplates/notification.html @@ -2,7 +2,7 @@ role="presentation" cellpadding="0" cellspacing="0" - style=" max-width: 560px;font-size:0px;width:100%;background: #fff; padding-bottom: 30px;box-shadow: 0px 0px 4px 0px rgba(0,0,0,0.2);border-radius: 10px;" + style="max-width: 560px;font-size:0px;width:100%;background: #fff; padding-bottom: 30px;box-shadow: 0px 0px 4px 0px rgba(0,0,0,0.2);border-radius: 10px;" align="center" border="0" > @@ -80,6 +80,7 @@ +
Click here to unsubscribe