2019-08-28 08:59:41 -04:00
|
|
|
const { callbackify } = require('util')
|
2019-05-29 05:21:06 -04:00
|
|
|
const logger = require('logger-sharelatex')
|
|
|
|
const Settings = require('settings-sharelatex')
|
|
|
|
const crypto = require('crypto')
|
|
|
|
const Mailchimp = require('mailchimp-api-v3')
|
2019-08-28 08:59:41 -04:00
|
|
|
const OError = require('@overleaf/o-error')
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2019-08-28 08:59:41 -04:00
|
|
|
const provider = getProvider()
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
subscribe: callbackify(provider.subscribe),
|
|
|
|
unsubscribe: callbackify(provider.unsubscribe),
|
|
|
|
changeEmail: callbackify(provider.changeEmail),
|
|
|
|
promises: provider
|
|
|
|
}
|
|
|
|
|
|
|
|
function getProvider() {
|
|
|
|
if (mailchimpIsConfigured()) {
|
|
|
|
logger.info('Using newsletter provider: mailchimp')
|
|
|
|
return makeMailchimpProvider()
|
|
|
|
} else {
|
|
|
|
logger.info('Using newsletter provider: none')
|
|
|
|
return makeNullProvider()
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-28 08:59:41 -04:00
|
|
|
function mailchimpIsConfigured() {
|
|
|
|
return Settings.mailchimp != null && Settings.mailchimp.api_key != null
|
|
|
|
}
|
|
|
|
|
|
|
|
function makeMailchimpProvider() {
|
|
|
|
const mailchimp = new Mailchimp(Settings.mailchimp.api_key)
|
|
|
|
const MAILCHIMP_LIST_ID = Settings.mailchimp.list_id
|
|
|
|
|
|
|
|
return {
|
|
|
|
subscribe,
|
|
|
|
unsubscribe,
|
|
|
|
changeEmail
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2019-08-28 08:59:41 -04:00
|
|
|
async function subscribe(user) {
|
|
|
|
try {
|
|
|
|
const path = getSubscriberPath(user.email)
|
|
|
|
await mailchimp.put(path, {
|
|
|
|
email_address: user.email,
|
|
|
|
status: 'subscribed',
|
|
|
|
status_if_new: 'subscribed',
|
|
|
|
merge_fields: getMergeFields(user)
|
|
|
|
})
|
|
|
|
logger.info({ user }, 'finished subscribing user to newsletter')
|
|
|
|
} catch (err) {
|
|
|
|
throw new OError({
|
|
|
|
message: 'error subscribing user to newsletter',
|
|
|
|
info: { userId: user._id }
|
|
|
|
}).withCause(err)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2019-08-28 08:59:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
async function unsubscribe(user) {
|
|
|
|
try {
|
|
|
|
const path = getSubscriberPath(user.email)
|
|
|
|
await mailchimp.put(path, {
|
|
|
|
email_address: user.email,
|
|
|
|
status: 'unsubscribed',
|
|
|
|
status_if_new: 'unsubscribed',
|
|
|
|
merge_fields: getMergeFields(user)
|
|
|
|
})
|
|
|
|
logger.info({ user }, 'finished unsubscribing user from newsletter')
|
|
|
|
} catch (err) {
|
|
|
|
if (err.message.includes('looks fake or invalid')) {
|
|
|
|
logger.info(
|
|
|
|
{ err, user },
|
|
|
|
'Mailchimp declined to unsubscribe user because it finds the email looks fake'
|
|
|
|
)
|
2019-05-29 05:21:06 -04:00
|
|
|
} else {
|
2019-08-28 08:59:41 -04:00
|
|
|
throw new OError({
|
|
|
|
message: 'error unsubscribing user from newsletter',
|
|
|
|
info: { userId: user._id }
|
|
|
|
}).withCause(err)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
}
|
2019-08-28 08:59:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
async function changeEmail(oldEmail, newEmail) {
|
|
|
|
try {
|
|
|
|
const path = getSubscriberPath(oldEmail)
|
|
|
|
await mailchimp.put(path, {
|
|
|
|
email_address: newEmail,
|
|
|
|
status_if_new: 'unsubscribed'
|
|
|
|
})
|
|
|
|
logger.info('finished changing email in the newsletter')
|
|
|
|
} catch (err) {
|
|
|
|
if (err.message.includes('merge fields were invalid')) {
|
|
|
|
logger.info(
|
2019-05-29 05:21:06 -04:00
|
|
|
{ oldEmail, newEmail },
|
|
|
|
'unable to change email in newsletter, user has never subscribed'
|
|
|
|
)
|
2019-08-28 08:59:41 -04:00
|
|
|
} else if (err.message.includes('could not be validated')) {
|
|
|
|
logger.info(
|
2019-05-29 05:21:06 -04:00
|
|
|
{ oldEmail, newEmail },
|
|
|
|
'unable to change email in newsletter, user has previously unsubscribed or new email already exist on list'
|
|
|
|
)
|
2019-08-28 08:59:41 -04:00
|
|
|
} else if (err.message.includes('is already a list member')) {
|
|
|
|
logger.info(
|
2019-05-29 05:21:06 -04:00
|
|
|
{ oldEmail, newEmail },
|
|
|
|
'unable to change email in newsletter, new email is already on mailing list'
|
|
|
|
)
|
2019-08-28 08:59:41 -04:00
|
|
|
} else if (err.message.includes('looks fake or invalid')) {
|
|
|
|
logger.info(
|
2019-05-29 05:21:06 -04:00
|
|
|
{ oldEmail, newEmail },
|
|
|
|
'unable to change email in newsletter, email looks fake to mailchimp'
|
|
|
|
)
|
|
|
|
} else {
|
2019-08-28 08:59:41 -04:00
|
|
|
throw new OError({
|
|
|
|
message: 'error changing email in newsletter',
|
|
|
|
info: { oldEmail, newEmail }
|
|
|
|
}).withCause(err)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2019-08-28 08:59:41 -04:00
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
|
2019-08-28 08:59:41 -04:00
|
|
|
function getSubscriberPath(email) {
|
|
|
|
const emailHash = hashEmail(email)
|
|
|
|
return `/lists/${MAILCHIMP_LIST_ID}/members/${emailHash}`
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
|
2019-08-28 08:59:41 -04:00
|
|
|
function hashEmail(email) {
|
|
|
|
return crypto
|
|
|
|
.createHash('md5')
|
|
|
|
.update(email.toLowerCase())
|
|
|
|
.digest('hex')
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
|
2019-08-28 08:59:41 -04:00
|
|
|
function getMergeFields(user) {
|
|
|
|
return {
|
2019-05-29 05:21:06 -04:00
|
|
|
FNAME: user.first_name,
|
|
|
|
LNAME: user.last_name,
|
2019-08-28 08:59:41 -04:00
|
|
|
MONGO_ID: user._id.toString()
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-28 08:59:41 -04:00
|
|
|
function makeNullProvider() {
|
|
|
|
return {
|
|
|
|
subscribe,
|
|
|
|
unsubscribe,
|
|
|
|
changeEmail
|
|
|
|
}
|
|
|
|
|
|
|
|
async function subscribe(user) {
|
|
|
|
logger.info(
|
|
|
|
{ user },
|
|
|
|
'Not subscribing user to newsletter because no newsletter provider is configured'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
async function unsubscribe(user) {
|
|
|
|
logger.info(
|
|
|
|
{ user },
|
|
|
|
'Not unsubscribing user from newsletter because no newsletter provider is configured'
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
async function changeEmail(oldEmail, newEmail) {
|
|
|
|
logger.info(
|
|
|
|
{ oldEmail, newEmail },
|
|
|
|
'Not changing email in newsletter for user because no newsletter provider is configured'
|
|
|
|
)
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|