mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-08-01 07:21:15 +00:00
Merge pull request #4968 from HabitRPG/paglias/emails-unsubscription-page
WIP Emails unsubscription page
This commit is contained in:
commit
e58521f416
9 changed files with 127 additions and 21 deletions
1
common/dist/scripts/habitrpg-shared.js
vendored
1
common/dist/scripts/habitrpg-shared.js
vendored
|
|
@ -7451,7 +7451,6 @@ process.browser = true;
|
|||
process.env = {};
|
||||
process.argv = [];
|
||||
process.version = ''; // empty string to avoid regexp issues
|
||||
process.versions = {};
|
||||
|
||||
function noop() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,9 @@
|
|||
"invitedQuest": "Invited to Quest",
|
||||
"kickedGroup": "Kicked from group",
|
||||
"remindersToLogin": "Reminders to check in to HabitRPG",
|
||||
"unsubscribedSuccessfully": "Unsubscribed successfully!",
|
||||
"unsubscribedTextUsers": "You have successfully unsubscribed from all HabitRPG emails. You can enable only the emails you want to receive from <a href=\"/#/options/settings/notifications\">the settings</a> (requires login).",
|
||||
"unsubscribedTextOthers": "You won't receive any other email from HabitRPG.",
|
||||
"unsubscribeAllEmails": "Check to Unsubscribe from Emails",
|
||||
"unsubscribeAllEmailsText": "By checking this box, I certify that I understand that by unsubscribing from all emails, HabitRPG will never be able to notify me via email about important changes to the site or my account.",
|
||||
"correctlyUnsubscribedEmailType": "Correctly unsubscribed from \"<%= emailType %>\" emails.",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ var utils = require('../utils');
|
|||
var nconf = require('nconf');
|
||||
var request = require('request');
|
||||
var User = require('../models/user').model;
|
||||
var EmailUnsubscription = require('../models/emailUnsubscription').model;
|
||||
var ga = require('./../utils').ga;
|
||||
var i18n = require('./../i18n');
|
||||
|
||||
|
|
@ -109,9 +110,14 @@ api.registerUser = function(req, res, next) {
|
|||
newUser.preferences = newUser.preferences || {};
|
||||
newUser.preferences.language = req.language; // User language detected from browser, not saved
|
||||
var user = new User(newUser);
|
||||
utils.txnEmail(user, 'welcome');
|
||||
ga.event('register', 'Local').send();
|
||||
user.save(cb);
|
||||
user.save(function(err, savedUser){
|
||||
// Clean previous email preferences
|
||||
EmailUnsubscription.remove({email: savedUser.auth.local.email}, function(){
|
||||
utils.txnEmail(savedUser, 'welcome');
|
||||
});
|
||||
cb.apply(cb, arguments);
|
||||
});
|
||||
}
|
||||
}]
|
||||
}, function(err, data) {
|
||||
|
|
@ -178,9 +184,16 @@ api.loginSocial = function(req, res, next) {
|
|||
};
|
||||
user.auth[network] = prof;
|
||||
user = new User(user);
|
||||
user.save(cb);
|
||||
user.save(function(err, savedUser){
|
||||
// Clean previous email preferences
|
||||
if(savedUser.auth.facebook.emails && savedUser.auth.facebook.emails[0] && savedUser.auth.facebook.emails[0].value){
|
||||
EmailUnsubscription.remove({email: savedUser.auth.facebook.emails[0].value}, function(){
|
||||
utils.txnEmail(savedUser, 'welcome');
|
||||
});
|
||||
}
|
||||
cb.apply(cb, arguments);
|
||||
});
|
||||
|
||||
utils.txnEmail(user, 'welcome');
|
||||
ga.event('register', network).send();
|
||||
}]
|
||||
}, function(err, results){
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ var shared = require('../../../common');
|
|||
var User = require('./../models/user').model;
|
||||
var Group = require('./../models/group').model;
|
||||
var Challenge = require('./../models/challenge').model;
|
||||
var EmailUnsubscription = require('./../models/emailUnsubscription').model;
|
||||
var isProd = nconf.get('NODE_ENV') === 'production';
|
||||
var api = module.exports;
|
||||
|
||||
|
|
@ -623,10 +624,15 @@ var inviteByEmails = function(invites, group, req, res, next){
|
|||
}
|
||||
|
||||
// TODO implement "users can only be invited once"
|
||||
invite.canSend = true; // Requested by utils.txnEmail
|
||||
utils.txnEmail(invite, ('invite-friend' + (group.type == 'guild' ? '-guild' : '')), variables);
|
||||
// Check for the email address not to be unsubscribed
|
||||
EmailUnsubscription.findOne({email: invite.email}, function(err, unsubscribed){
|
||||
if(err) return cb(err);
|
||||
if(unsubscribed) return cb();
|
||||
|
||||
cb();
|
||||
utils.txnEmail(invite, ('invite-friend' + (group.type == 'guild' ? '-guild' : '')), variables);
|
||||
|
||||
cb();
|
||||
});
|
||||
});
|
||||
}else{
|
||||
cb();
|
||||
|
|
|
|||
36
website/src/controllers/unsubscription.js
Normal file
36
website/src/controllers/unsubscription.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
var User = require('../models/user').model;
|
||||
var EmailUnsubscription = require('../models/emailUnsubscription').model;
|
||||
var utils = require('../utils');
|
||||
var i18n = require('../../../common').i18n;
|
||||
|
||||
var api = module.exports = {};
|
||||
|
||||
api.unsubscribe = function(req, res, next){
|
||||
if(!req.query.code) return res.json(500, {err: 'Missing unsubscription code.'});
|
||||
|
||||
var data = JSON.parse(utils.decrypt(req.query.code));
|
||||
|
||||
if(data._id){
|
||||
User.update({_id: data._id}, {
|
||||
$set: {'preferences.emailNotifications.unsubscribeFromAll': true}
|
||||
}, {multi: false}, function(err, nAffected){
|
||||
if(err) return next(err);
|
||||
if(nAffected !== 1) return res.json(404, {err: 'User not found'});
|
||||
|
||||
res.send('<h1>' + i18n.t('unsubscribedSuccessfully', null, req.language) + '</h1>' + i18n.t('unsubscribedTextUsers', null, req.language));
|
||||
});
|
||||
}else{
|
||||
EmailUnsubscription.findOne({email: data.email}, function(err, doc){
|
||||
if(err) return next(err);
|
||||
var okRes = '<h1>' + i18n.t('unsubscribedSuccessfully', null, req.language) + '</h1>' + i18n.t('unsubscribedTextOthers', null, req.language);
|
||||
|
||||
if(doc) return res.send(okRes);
|
||||
|
||||
EmailUnsubscription.create({email: data.email}, function(err, doc){
|
||||
if(err) return next(err);
|
||||
|
||||
res.send(okRes);
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
14
website/src/models/emailUnsubscription.js
Normal file
14
website/src/models/emailUnsubscription.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
var mongoose = require("mongoose");
|
||||
var shared = require('../../../common');
|
||||
|
||||
// A collection used to store mailing list unsubscription for non registered email addresses
|
||||
var EmailUnsubscriptionSchema = new mongoose.Schema({
|
||||
_id: {
|
||||
type: String,
|
||||
'default': shared.uuid
|
||||
},
|
||||
email: String
|
||||
});
|
||||
|
||||
module.exports.schema = EmailUnsubscriptionSchema;
|
||||
module.exports.model = mongoose.model('EmailUnsubscription', EmailUnsubscriptionSchema);
|
||||
8
website/src/routes/unsubscription.js
Normal file
8
website/src/routes/unsubscription.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
var express = require('express');
|
||||
var router = new express.Router();
|
||||
var i18n = require('../i18n');
|
||||
var unsubscription = require('../controllers/unsubscription');
|
||||
|
||||
router.get('/unsubscribe', i18n.getUserLanguage, unsubscription.unsubscribe);
|
||||
|
||||
module.exports = router;
|
||||
|
|
@ -127,6 +127,7 @@ if (cores!==0 && cluster.isMaster && (isDev || isProd)) {
|
|||
app.use(require('./routes/payments').middleware);
|
||||
app.use(require('./routes/auth').middleware);
|
||||
app.use(require('./routes/coupon').middleware);
|
||||
app.use(require('./routes/unsubscription').middleware);
|
||||
var v2 = express();
|
||||
app.use('/api/v2', v2);
|
||||
app.use('/api/v1', require('./routes/apiv1').middleware);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,10 @@ function getUserInfo(user, fields) {
|
|||
}
|
||||
}
|
||||
|
||||
if(fields.indexOf('_id') != -1){
|
||||
info._id = user._id;
|
||||
}
|
||||
|
||||
if(fields.indexOf('canSend') != -1){
|
||||
info.canSend = user.preferences.emailNotifications.unsubscribeFromAll !== true;
|
||||
}
|
||||
|
|
@ -62,37 +66,59 @@ module.exports.txnEmail = function(mailingInfoArray, emailType, variables, perso
|
|||
|
||||
// It's important to pass at least a user with its `preferences` as we need to check if he unsubscribed
|
||||
mailingInfoArray = mailingInfoArray.map(function(mailingInfo){
|
||||
return mailingInfo._id ? getUserInfo(mailingInfo, ['email', 'name', 'canSend']) : mailingInfo;
|
||||
return mailingInfo._id ? getUserInfo(mailingInfo, ['_id', 'email', 'name', 'canSend']) : mailingInfo;
|
||||
}).filter(function(mailingInfo){
|
||||
// Always send reset-password emails
|
||||
return (mailingInfo.email && (mailingInfo.canSend || emailType === 'reset-password'));
|
||||
// Don't check canSend for non registered users as already checked before
|
||||
return (mailingInfo.email && ((!mailingInfo._id || mailingInfo.canSend) || emailType === 'reset-password'));
|
||||
});
|
||||
|
||||
// Personal variables are personal to each email recipient, if they are missing
|
||||
// we manually create a structure for them with RECIPIENT_NAME
|
||||
// otherwise we just add RECIPIENT_NAME to the existing personal variables
|
||||
// we manually create a structure for them with RECIPIENT_NAME and RECIPIENT_UNSUB_URL
|
||||
// otherwise we just add RECIPIENT_NAME and RECIPIENT_UNSUB_URL to the existing personal variables
|
||||
if(!personalVariables || personalVariables.length === 0){
|
||||
personalVariables = mailingInfoArray.map(function(mailingInfo){
|
||||
return {
|
||||
rcpt: mailingInfo.email,
|
||||
vars: [{
|
||||
name: 'RECIPIENT_NAME',
|
||||
content: mailingInfo.name
|
||||
}]
|
||||
vars: [
|
||||
{
|
||||
name: 'RECIPIENT_NAME',
|
||||
content: mailingInfo.name
|
||||
},
|
||||
{
|
||||
name: 'RECIPIENT_UNSUB_URL',
|
||||
content: baseUrl + '/unsubscribe?code=' + module.exports.encrypt(JSON.stringify({
|
||||
_id: mailingInfo._id,
|
||||
email: mailingInfo.email
|
||||
}))
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
}else{
|
||||
var temporaryPersonalVariables = {};
|
||||
|
||||
mailingInfoArray.forEach(function(mailingInfo){
|
||||
temporaryPersonalVariables[mailingInfo.email] = mailingInfo.name;
|
||||
temporaryPersonalVariables[mailingInfo.email] = {
|
||||
name: mailingInfo.name,
|
||||
_id: mailingInfo._id
|
||||
}
|
||||
});
|
||||
|
||||
personalVariables.forEach(function(singlePersonalVariables){
|
||||
singlePersonalVariables.vars.push({
|
||||
name: 'RECIPIENT_NAME',
|
||||
content: temporaryPersonalVariables[singlePersonalVariables.rcpt]
|
||||
});
|
||||
singlePersonalVariables.vars.push(
|
||||
{
|
||||
name: 'RECIPIENT_NAME',
|
||||
content: temporaryPersonalVariables[singlePersonalVariables.rcpt].name
|
||||
},
|
||||
{
|
||||
name: 'RECIPIENT_UNSUB_URL',
|
||||
content: baseUrl + '/unsubscribe?code=' + module.exports.encrypt(JSON.stringify({
|
||||
_id: temporaryPersonalVariables[singlePersonalVariables.rcpt]._id,
|
||||
email: singlePersonalVariables.rcpt
|
||||
}))
|
||||
}
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue