From 91795875b51b62b65a5b264e964573f389cc4d64 Mon Sep 17 00:00:00 2001 From: Sabe Jones Date: Wed, 7 Feb 2024 16:09:23 -0600 Subject: [PATCH] feat(email): allow unsub via POST request --- website/server/controllers/top-level/email.js | 81 +++++++++++++------ 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/website/server/controllers/top-level/email.js b/website/server/controllers/top-level/email.js index 3db8f95b2d..72074907f1 100644 --- a/website/server/controllers/top-level/email.js +++ b/website/server/controllers/top-level/email.js @@ -7,6 +7,36 @@ import { const api = {}; +async function emailUnsubscribe (req, res) { + req.checkQuery({ + code: { + notEmpty: { errorMessage: res.t('missingUnsubscriptionCode') }, + }, + }); + const validationErrors = req.validationErrors(); + if (validationErrors) throw validationErrors; + + const data = JSON.parse(decrypt(req.query.code)); + + if (data._id) { + const userUpdated = await User.updateOne( + { _id: data._id }, + { $set: { 'preferences.emailNotifications.unsubscribeFromAll': true } }, + ).exec(); + + if (userUpdated.modifiedCount !== 1) throw new NotFound(res.t('userNotFound')); + + res.send(`

${res.t('unsubscribedSuccessfully')}

${res.t('unsubscribedTextUsers')}`); + } else { + const unsubscribedEmail = await EmailUnsubscription + .findOne({ email: data.email.toLowerCase() }).exec(); + if (!unsubscribedEmail) await EmailUnsubscription.create({ email: data.email.toLowerCase() }); + + const okResponse = `

${res.t('unsubscribedSuccessfully')}

${res.t('unsubscribedTextOthers')}`; + res.send(okResponse); + } +} + /** * @api {get} /email/unsubscribe Unsubscribe an email address or user from email notifications * @apiName UnsubscribeEmail @@ -27,33 +57,32 @@ api.unsubscribe = { method: 'GET', url: '/email/unsubscribe', async handler (req, res) { - req.checkQuery({ - code: { - notEmpty: { errorMessage: res.t('missingUnsubscriptionCode') }, - }, - }); - const validationErrors = req.validationErrors(); - if (validationErrors) throw validationErrors; + await emailUnsubscribe(req, res); + }, +}; - const data = JSON.parse(decrypt(req.query.code)); - - if (data._id) { - const userUpdated = await User.updateOne( - { _id: data._id }, - { $set: { 'preferences.emailNotifications.unsubscribeFromAll': true } }, - ).exec(); - - if (userUpdated.modifiedCount !== 1) throw new NotFound(res.t('userNotFound')); - - res.send(`

${res.t('unsubscribedSuccessfully')}

${res.t('unsubscribedTextUsers')}`); - } else { - const unsubscribedEmail = await EmailUnsubscription - .findOne({ email: data.email.toLowerCase() }).exec(); - if (!unsubscribedEmail) await EmailUnsubscription.create({ email: data.email.toLowerCase() }); - - const okResponse = `

${res.t('unsubscribedSuccessfully')}

${res.t('unsubscribedTextOthers')}`; - res.send(okResponse); - } +/** + * @api {post} /email/unsubscribe Unsubscribe an email address or user from email notifications + * @apiName OneClickUnsubscribe + * @apiGroup Unsubscribe + * @apiDescription This is a POST method for compliance with RFC 8058. It works identically to the + * GET method on the same URI, allowing the user to unsubscribe from emails either via visiting a + * hyperlink or activating a one-click Unsubscribe button in their email client. + * Does not require authentication. + * + * @apiParam (Query) {String} code An unsubscription code that contains an encrypted User ID or + * email address + * + * @apiSuccess {String} Webpage An html success message + * + * @apiError (400) {BadRequest} missingUnsubscriptionCode The unsubscription code is missing. + * @apiUse UserNotFound + */ +api.oneClickUnsubscribe = { + method: 'POST', + url: '/email/unsubscribe', + async handler (req, res) { + await emailUnsubscribe(req, res); }, };