From c3a4bcb116f4143f074bfe678baadd22fdd8ba47 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 15 Apr 2014 21:45:36 -0400 Subject: [PATCH 1/3] first pass #1249 -- this causes emails to be sent if you have not been to the site in over 24 hours. --- src/routes/debug.js | 2 +- src/user/jobs.js | 53 +++++++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/routes/debug.js b/src/routes/debug.js index 6c03961251..c49dfc7c2b 100644 --- a/src/routes/debug.js +++ b/src/routes/debug.js @@ -54,7 +54,7 @@ module.exports = function(app, middleware, controllers) { }); app.get('/test', function(req, res) { - require('../meta').sounds.init(); + user.sendDailyDigests(); res.send(200); }); }); diff --git a/src/user/jobs.js b/src/user/jobs.js index 602b889039..c28519eecf 100644 --- a/src/user/jobs.js +++ b/src/user/jobs.js @@ -8,7 +8,6 @@ var db = require('../database'), nconf = require('nconf'), user = require('../user'), - UserNotifications = require('./notifications'), topics = require('../topics'), emailer = require('../emailer'), meta = require('../meta'); @@ -23,6 +22,8 @@ module.exports = function(User) { }; User.sendDailyDigests = function() { + var yesterday = Date.now() - (1000*60*60*24); + async.parallel({ recent: function(next) { topics.getLatestTopics(0, 0, 10, 'day', next); @@ -33,39 +34,43 @@ module.exports = function(User) { }, function(err, data) { var now = new Date(); - async.each(data.uids, function(uid, next) { - UserNotifications.getDailyUnread(uid, function(err, notifications) { - if (!err && notifications && notifications.length) { + // Consider using eachLimit, but *only* if people complain about email relays choking -- otherwise we're ok. + User.getMultipleUserFields(data.uids, ['uid', 'username', 'lastonline'], function(err, receipients) { + // Find only those users who have not been online in the past 24 hours + var users = receipients.filter(function(userObj) { + return yesterday > parseInt(userObj.lastonline, 10); + }); + async.each(users, function(userObj, next) { + user.notifications.getDailyUnread(userObj.uid, function(err, notifications) { + // Turn relative URLs into absolute ones for(var i=0; i Date: Wed, 16 Apr 2014 16:47:51 -0400 Subject: [PATCH 2/3] daily digest settings in User Settings --- public/language/en_GB/global.json | 2 +- public/language/en_GB/user.json | 6 ++++++ public/src/forum/accountsettings.js | 6 +++--- src/user/jobs.js | 2 +- src/user/settings.js | 5 ++++- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/public/language/en_GB/global.json b/public/language/en_GB/global.json index c935f1c5d8..de15a7e4ce 100644 --- a/public/language/en_GB/global.json +++ b/public/language/en_GB/global.json @@ -69,6 +69,6 @@ "invisible": "Invisible", "offline": "Offline", - "privacy": "Privacy", + "email": "Email", "language": "Language" } diff --git a/public/language/en_GB/user.json b/public/language/en_GB/user.json index 1ca6651efb..a9a384da43 100644 --- a/public/language/en_GB/user.json +++ b/public/language/en_GB/user.json @@ -47,6 +47,12 @@ "settings": "Settings", "show_email": "Show My Email", + "digest_label": "Subscribe to Digest", + "digest_description": "Subscribe to email updates for this forum (new notifications and topics) according to a set schedule", + "digest_off": "Off", + "digest_daily": "Daily", + "digest_weekly": "Weekly", + "digest_monthly": "Monthly", "has_no_follower": "This user doesn't have any followers :(", "follows_no_one": "This user isn't following anyone :(", diff --git a/public/src/forum/accountsettings.js b/public/src/forum/accountsettings.js index bb18cacb2c..4945eb8abb 100644 --- a/public/src/forum/accountsettings.js +++ b/public/src/forum/accountsettings.js @@ -16,11 +16,11 @@ define(['forum/accountheader'], function(header) { } switch (input.attr('type')) { - case 'text' : - case 'textarea' : + case 'text': + case 'textarea': settings[setting] = input.val(); break; - case 'checkbox' : + case 'checkbox': settings[setting] = input.is(':checked') ? 1 : 0; break; } diff --git a/src/user/jobs.js b/src/user/jobs.js index c28519eecf..520075281c 100644 --- a/src/user/jobs.js +++ b/src/user/jobs.js @@ -34,13 +34,13 @@ module.exports = function(User) { }, function(err, data) { var now = new Date(); - // Consider using eachLimit, but *only* if people complain about email relays choking -- otherwise we're ok. User.getMultipleUserFields(data.uids, ['uid', 'username', 'lastonline'], function(err, receipients) { // Find only those users who have not been online in the past 24 hours var users = receipients.filter(function(userObj) { return yesterday > parseInt(userObj.lastonline, 10); }); + // Consider using eachLimit, but *only* if people complain about email relays choking -- otherwise we're ok. async.each(users, function(userObj, next) { user.notifications.getDailyUnread(userObj.uid, function(err, notifications) { // Turn relative URLs into absolute ones diff --git a/src/user/settings.js b/src/user/settings.js index ab80e4fb42..6dd9b6817e 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -25,6 +25,7 @@ module.exports = function(User) { settings = data.settings; settings.showemail = settings.showemail ? parseInt(settings.showemail, 10) !== 0 : false; + settings.enableDailyDigest = settings.enableDailyDigest || 'daily'; settings.usePagination = settings.usePagination ? parseInt(settings.usePagination, 10) === 1 : parseInt(meta.config.usePagination, 10) === 1; settings.topicsPerPage = settings.topicsPerPage ? parseInt(settings.topicsPerPage, 10) : parseInt(meta.config.topicsPerPage, 10) || 20; settings.postsPerPage = settings.postsPerPage ? parseInt(settings.postsPerPage, 10) : parseInt(meta.config.postsPerPage, 10) || 10; @@ -41,10 +42,12 @@ module.exports = function(User) { return callback(new Error('[[error:invalid-pagination-value]]')); } - plugins.fireHook('action:user.saveSettings', {uid: uid, settings: data}); + data.language = data.language || meta.config.defaultLang; + plugins.fireHook('action:user.saveSettings', {uid: uid, settings: data}); db.setObject('user:' + uid + ':settings', { showemail: data.showemail, + enableDailyDigest: data.enableDailyDigest || 'daily', usePagination: data.usePagination, topicsPerPage: data.topicsPerPage, postsPerPage: data.postsPerPage, From dc051b906024ec502ebbce6bb67da2c6f49af162 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 16 Apr 2014 17:38:34 -0400 Subject: [PATCH 3/3] final pass #1249 --- src/routes/debug.js | 1 - src/user/jobs.js | 24 +++++++++++++++++++++--- src/user/settings.js | 29 +++++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/routes/debug.js b/src/routes/debug.js index c49dfc7c2b..ca7a13b665 100644 --- a/src/routes/debug.js +++ b/src/routes/debug.js @@ -54,7 +54,6 @@ module.exports = function(app, middleware, controllers) { }); app.get('/test', function(req, res) { - user.sendDailyDigests(); res.send(200); }); }); diff --git a/src/user/jobs.js b/src/user/jobs.js index 520075281c..c2e88e752f 100644 --- a/src/user/jobs.js +++ b/src/user/jobs.js @@ -34,10 +34,28 @@ module.exports = function(User) { }, function(err, data) { var now = new Date(); - User.getMultipleUserFields(data.uids, ['uid', 'username', 'lastonline'], function(err, receipients) { + async.parallel({ + recipients: function(next) { + User.getMultipleUserFields(data.uids, ['uid', 'username', 'lastonline'], next); + }, + userSettings: function(next) { + User.getMultipleUserSettings(data.uids, next); + } + }, function(err, users) { + var recipients = users.recipients, + userSettings = users.userSettings, + subscribed; + + // Find uids subscribed to daily digest emails + subscribed = userSettings.filter(function(setting) { + return !setting.dailyDigestFreq || setting.dailyDigestFreq === 'daily'; + }).map(function(setting) { + return setting.uid; + }); + // Find only those users who have not been online in the past 24 hours - var users = receipients.filter(function(userObj) { - return yesterday > parseInt(userObj.lastonline, 10); + var users = recipients.filter(function(userObj) { + return subscribed.indexOf(userObj.uid) !== -1 && yesterday > parseInt(userObj.lastonline, 10); }); // Consider using eachLimit, but *only* if people complain about email relays choking -- otherwise we're ok. diff --git a/src/user/settings.js b/src/user/settings.js index 6dd9b6817e..781b1934f5 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -25,7 +25,7 @@ module.exports = function(User) { settings = data.settings; settings.showemail = settings.showemail ? parseInt(settings.showemail, 10) !== 0 : false; - settings.enableDailyDigest = settings.enableDailyDigest || 'daily'; + settings.dailyDigestFreq = settings.dailyDigestFreq || 'daily'; settings.usePagination = settings.usePagination ? parseInt(settings.usePagination, 10) === 1 : parseInt(meta.config.usePagination, 10) === 1; settings.topicsPerPage = settings.topicsPerPage ? parseInt(settings.topicsPerPage, 10) : parseInt(meta.config.topicsPerPage, 10) || 20; settings.postsPerPage = settings.postsPerPage ? parseInt(settings.postsPerPage, 10) : parseInt(meta.config.postsPerPage, 10) || 10; @@ -36,6 +36,31 @@ module.exports = function(User) { }); }; + User.getMultipleUserSettings = function(uids, callback) { + if (!Array.isArray(uids) || !uids.length) { + return callback(null, []); + } + + var keys = uids.map(function(uid) { + return 'user:' + uid + ':settings'; + }); + + db.getObjects(keys, function(err, settings) { + if (err) { + return callback(err); + } + + // Associate uid + settings = settings.map(function(setting, idx) { + setting = setting || {}; + setting.uid = uids[idx]; + return setting; + }); + + callback(null, settings); + }); + }; + User.saveSettings = function(uid, data, callback) { if(!data.topicsPerPage || !data.postsPerPage || parseInt(data.topicsPerPage, 10) <= 0 || parseInt(data.postsPerPage, 10) <= 0) { @@ -47,7 +72,7 @@ module.exports = function(User) { plugins.fireHook('action:user.saveSettings', {uid: uid, settings: data}); db.setObject('user:' + uid + ':settings', { showemail: data.showemail, - enableDailyDigest: data.enableDailyDigest || 'daily', + dailyDigestFreq: data.dailyDigestFreq || 'daily', usePagination: data.usePagination, topicsPerPage: data.topicsPerPage, postsPerPage: data.postsPerPage,