From 1d26fc0d893956c4dfd7e58f216d24ca28b31069 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Tue, 6 Jun 2017 12:55:43 -0400 Subject: [PATCH 01/96] closes #5741 --- src/categories/topics.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/categories/topics.js b/src/categories/topics.js index 50278f529b..88151973a7 100644 --- a/src/categories/topics.js +++ b/src/categories/topics.js @@ -13,7 +13,7 @@ module.exports = function (Categories) { plugins.fireHook('filter:category.topics.prepare', data, next); }, function (data, next) { - Categories.getTopicIds(data.cid, data.set, data.reverse, data.start, data.stop, next); + Categories.getTopicIds(data, next); }, function (tids, next) { topics.getTopicsByTids(tids, data.uid, next); @@ -35,14 +35,18 @@ module.exports = function (Categories) { ], callback); }; - Categories.getTopicIds = function (cid, set, reverse, start, stop, callback) { + Categories.getTopicIds = function (data, callback) { var pinnedTids; var pinnedCount; var totalPinnedCount; + var start = data.start; + var stop = data.stop; + var set = data.set; + async.waterfall([ function (next) { - Categories.getPinnedTids(cid, 0, -1, next); + Categories.getPinnedTids(data.cid, 0, -1, next); }, function (_pinnedTids, next) { totalPinnedCount = _pinnedTids.length; @@ -64,9 +68,9 @@ module.exports = function (Categories) { stop = stop === -1 ? stop : start + normalTidsToGet - 1; if (Array.isArray(set)) { - db[reverse ? 'getSortedSetRevIntersect' : 'getSortedSetIntersect']({ sets: set, start: start, stop: stop }, next); + db[data.reverse ? 'getSortedSetRevIntersect' : 'getSortedSetIntersect']({ sets: set, start: start, stop: stop }, next); } else { - db[reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'](set, start, stop, next); + db[data.reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'](set, start, stop, next); } }, function (normalTids, next) { From 037a0e523981451c6db967c6f0d08d6abe267af0 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Tue, 6 Jun 2017 16:40:32 -0400 Subject: [PATCH 02/96] closes #5742 also fix reverse infinite scroll when sorting is changed --- public/src/client/category.js | 5 +- src/categories.js | 8 +--- src/categories/topics.js | 89 +++++++++++++++++++++++++++++------ src/controllers/category.js | 48 +++++-------------- src/socket.io/categories.js | 35 ++++---------- src/topics/recent.js | 7 ++- src/topics/suggested.js | 6 ++- test/categories.js | 46 ++++++++++++++---- 8 files changed, 151 insertions(+), 93 deletions(-) diff --git a/public/src/client/category.js b/public/src/client/category.js index 4cdd18ca2b..3cf9121659 100644 --- a/public/src/client/category.js +++ b/public/src/client/category.js @@ -264,7 +264,7 @@ define('forum/category', [ var topics = $('[component="category/topic"]'); var afterEl = direction > 0 ? topics.last() : topics.first(); - var after = (parseInt(afterEl.attr('data-index'), 10) || 0) + 1; + var after = (parseInt(afterEl.attr('data-index'), 10) || 0) + (direction > 0 ? 1 : 0); loadTopicsAfter(after, direction); }; @@ -281,8 +281,7 @@ define('forum/category', [ cid: ajaxify.data.cid, after: after, direction: direction, - author: params.author, - tag: params.tag, + query: params, categoryTopicSort: config.categoryTopicSort, }, function (data, done) { if (data.topics && data.topics.length) { diff --git a/src/categories.js b/src/categories.js index 4fd6ec3b1f..1487b543e2 100644 --- a/src/categories.js +++ b/src/categories.js @@ -35,17 +35,13 @@ Categories.getCategoryById = function (data, callback) { return next(new Error('[[error:invalid-cid]]')); } category = categories[0]; - + data.category = category; async.parallel({ topics: function (next) { Categories.getCategoryTopics(data, next); }, topicCount: function (next) { - if (Array.isArray(data.set)) { - db.sortedSetIntersectCard(data.set, next); - } else { - next(null, category.topic_count); - } + Categories.getTopicCount(data, next); }, isIgnored: function (next) { Categories.isIgnored([data.cid], data.uid, next); diff --git a/src/categories/topics.js b/src/categories/topics.js index 88151973a7..bedf6e81c7 100644 --- a/src/categories/topics.js +++ b/src/categories/topics.js @@ -5,6 +5,7 @@ var async = require('async'); var db = require('../database'); var topics = require('../topics'); var plugins = require('../plugins'); +var meta = require('../meta'); module.exports = function (Categories) { Categories.getCategoryTopics = function (data, callback) { @@ -37,40 +38,52 @@ module.exports = function (Categories) { Categories.getTopicIds = function (data, callback) { var pinnedTids; - var pinnedCount; - var totalPinnedCount; - - var start = data.start; - var stop = data.stop; - var set = data.set; async.waterfall([ function (next) { Categories.getPinnedTids(data.cid, 0, -1, next); }, function (_pinnedTids, next) { - totalPinnedCount = _pinnedTids.length; + var totalPinnedCount = _pinnedTids.length; - pinnedTids = _pinnedTids.slice(start, stop === -1 ? undefined : stop + 1); + pinnedTids = _pinnedTids.slice(data.start, data.stop === -1 ? undefined : data.stop + 1); - pinnedCount = pinnedTids.length; + var pinnedCount = pinnedTids.length; - var topicsPerPage = stop - start + 1; + var topicsPerPage = data.stop - data.start + 1; var normalTidsToGet = Math.max(0, topicsPerPage - pinnedCount); - if (!normalTidsToGet && stop !== -1) { + if (!normalTidsToGet && data.stop !== -1) { return next(null, []); } + + if (plugins.hasListeners('filter:categories.getTopicIds')) { + return plugins.fireHook('filter:categories.getTopicIds', { + tids: [], + data: data, + pinnedTids: pinnedTids, + allPinnedTids: _pinnedTids, + totalPinnedCount: totalPinnedCount, + normalTidsToGet: normalTidsToGet, + }, function (err, data) { + callback(err, data && data.tids); + }); + } + + var set = Categories.buildTopicsSortedSet(data); + var reverse = Categories.getSortedSetRangeDirection(data.sort); + var start = data.start; if (start > 0 && totalPinnedCount) { start -= totalPinnedCount - pinnedCount; } - stop = stop === -1 ? stop : start + normalTidsToGet - 1; + + var stop = data.stop === -1 ? data.stop : start + normalTidsToGet - 1; if (Array.isArray(set)) { - db[data.reverse ? 'getSortedSetRevIntersect' : 'getSortedSetIntersect']({ sets: set, start: start, stop: stop }, next); + db[reverse ? 'getSortedSetRevIntersect' : 'getSortedSetIntersect']({ sets: set, start: start, stop: stop }, next); } else { - db[data.reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'](set, start, stop, next); + db[reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'](set, start, stop, next); } }, function (normalTids, next) { @@ -83,6 +96,54 @@ module.exports = function (Categories) { ], callback); }; + Categories.getTopicCount = function (data, callback) { + if (plugins.hasListeners('filter:categories.getTopicCount')) { + return plugins.fireHook('filter:categories.getTopicCount', { + topicCount: data.category.topic_count, + data: data, + }, function (err, data) { + callback(err, data && data.topicCount); + }); + } + var set = Categories.buildTopicsSortedSet(data); + if (Array.isArray(set)) { + db.sortedSetIntersectCard(set, callback); + } else { + callback(null, data.category.topic_count); + } + }; + + Categories.buildTopicsSortedSet = function (data) { + var cid = data.cid; + var set = 'cid:' + cid + ':tids'; + var sort = data.sort || (data.settings && data.settings.categoryTopicSort) || meta.config.categoryTopicSort || 'newest_to_oldest'; + + if (sort === 'most_posts') { + set = 'cid:' + cid + ':tids:posts'; + } + + if (data.targetUid) { + set = 'cid:' + cid + ':uid:' + data.targetUid + ':tids'; + } + + if (data.tag) { + if (Array.isArray(data.tag)) { + set = [set].concat(data.tag.map(function (tag) { + return 'tag:' + tag + ':topics'; + })); + } else { + set = [set, 'tag:' + data.tag + ':topics']; + } + } + return set; + }; + + Categories.getSortedSetRangeDirection = function (sort) { + sort = sort || 'newest_to_oldest'; + var reverse = sort === 'newest_to_oldest' || sort === 'most_posts'; + return reverse; + }; + Categories.getAllTopicIds = function (cid, start, stop, callback) { db.getSortedSetRange(['cid:' + cid + ':tids:pinned', 'cid:' + cid + ':tids'], start, stop, callback); }; diff --git a/src/controllers/category.js b/src/controllers/category.js index cb5b08f9a3..495b1fc9f2 100644 --- a/src/controllers/category.js +++ b/src/controllers/category.js @@ -77,49 +77,27 @@ categoryController.get = function (req, res, callback) { topicIndex = 0; } - var set = 'cid:' + cid + ':tids'; - var reverse = false; - // `sort` qs has priority over user setting var sort = req.query.sort || settings.categoryTopicSort; - if (sort === 'newest_to_oldest') { - reverse = true; - } else if (sort === 'most_posts') { - reverse = true; - set = 'cid:' + cid + ':tids:posts'; - } - var start = ((currentPage - 1) * settings.topicsPerPage) + topicIndex; var stop = start + settings.topicsPerPage - 1; - var payload = { - cid: cid, - set: set, - reverse: reverse, - start: start, - stop: stop, - uid: req.uid, - settings: settings, - }; - async.waterfall([ function (next) { user.getUidByUserslug(req.query.author, next); }, - function (uid, next) { - payload.targetUid = uid; - if (uid) { - payload.set = 'cid:' + cid + ':uid:' + uid + ':tids'; - } - - if (req.query.tag) { - if (Array.isArray(req.query.tag)) { - payload.set = [payload.set].concat(req.query.tag.map(function (tag) { - return 'tag:' + tag + ':topics'; - })); - } else { - payload.set = [payload.set, 'tag:' + req.query.tag + ':topics']; - } - } + function (targetUid, next) { + var payload = { + uid: req.uid, + cid: cid, + start: start, + stop: stop, + sort: sort, + settings: settings, + query: req.query, + tag: req.query.tag, + targetUid: targetUid, + }; + categories.getCategoryById(payload, next); }, ], next); diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index db47d0e865..9dfb285d82 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -59,6 +59,7 @@ SocketCategories.loadMore = function (socket, data, callback) { if (!data) { return callback(new Error('[[error:invalid-data]]')); } + data.query = data.query || {}; var userPrivileges; async.waterfall([ function (next) { @@ -70,8 +71,8 @@ SocketCategories.loadMore = function (socket, data, callback) { user.getSettings(socket.uid, next); }, targetUid: function (next) { - if (data.author) { - user.getUidByUserslug(data.author, next); + if (data.query.author) { + user.getUidByUserslug(data.query.author, next); } else { next(); } @@ -84,44 +85,28 @@ SocketCategories.loadMore = function (socket, data, callback) { return callback(new Error('[[error:no-privileges]]')); } var infScrollTopicsPerPage = 20; - var set = 'cid:' + data.cid + ':tids'; - var reverse = false; - - if (data.categoryTopicSort === 'newest_to_oldest') { - reverse = true; - } else if (data.categoryTopicSort === 'most_posts') { - reverse = true; - set = 'cid:' + data.cid + ':tids:posts'; - } + var sort = data.sort || data.categoryTopicSort; var start = Math.max(0, parseInt(data.after, 10)); if (data.direction === -1) { - start -= reverse ? infScrollTopicsPerPage : -infScrollTopicsPerPage; + start -= infScrollTopicsPerPage; } var stop = start + infScrollTopicsPerPage - 1; start = Math.max(0, start); stop = Math.max(0, stop); - - if (results.targetUid) { - set = 'cid:' + data.cid + ':uid:' + results.targetUid + ':tids'; - } - - if (data.tag) { - set = [set, 'tag:' + data.tag + ':topics']; - } - categories.getCategoryTopics({ + uid: socket.uid, cid: data.cid, - set: set, - reverse: reverse, start: start, stop: stop, - uid: socket.uid, - targetUid: results.targetUid, + sort: sort, settings: results.settings, + query: data.query, + tag: data.query.tag, + targetUid: results.targetUid, }, next); }, function (data, next) { diff --git a/src/topics/recent.js b/src/topics/recent.js index b2e0de6023..7190c0e36b 100644 --- a/src/topics/recent.js +++ b/src/topics/recent.js @@ -27,7 +27,12 @@ module.exports = function (Topics) { async.waterfall([ function (next) { if (cid) { - categories.getTopicIds(cid, 'cid:' + cid + ':tids', true, 0, 199, next); + categories.getTopicIds({ + cid: cid, + start: 0, + stop: 199, + sort: 'newest_to_oldest', + }, next); } else { db.getSortedSetRevRange('topics:recent', 0, 199, next); } diff --git a/src/topics/suggested.js b/src/topics/suggested.js index 33153a580c..f144c4cc79 100644 --- a/src/topics/suggested.js +++ b/src/topics/suggested.js @@ -73,7 +73,11 @@ module.exports = function (Topics) { Topics.getTopicField(tid, 'cid', next); }, function (cid, next) { - categories.getTopicIds(cid, 'cid:' + cid + ':tids', true, 0, 9, next); + categories.getTopicIds({ + cid: cid, + start: 0, + stop: 9, + }, next); }, ], callback); } diff --git a/test/categories.js b/test/categories.js index 9c481fc317..5533a2d9ab 100644 --- a/test/categories.js +++ b/test/categories.js @@ -54,8 +54,6 @@ describe('Categories', function () { it('should retrieve a newly created category by its ID', function (done) { Categories.getCategoryById({ cid: categoryObj.cid, - set: 'cid:' + categoryObj.cid + ':tids', - reverse: true, start: 0, stop: -1, uid: 0, @@ -103,11 +101,10 @@ describe('Categories', function () { it('should return a list of topics', function (done) { Categories.getCategoryTopics({ cid: categoryObj.cid, - set: 'cid:' + categoryObj.cid + ':tids', - reverse: true, start: 0, stop: 10, uid: 0, + sort: 'oldest-to-newest', }, function (err, result) { assert.equal(err, null); @@ -123,12 +120,11 @@ describe('Categories', function () { it('should return a list of topics by a specific user', function (done) { Categories.getCategoryTopics({ cid: categoryObj.cid, - set: 'cid:' + categoryObj.cid + ':uid:' + 1 + ':tids', - reverse: true, start: 0, stop: 10, uid: 0, targetUid: 1, + sort: 'oldest-to-newest', }, function (err, result) { assert.equal(err, null); assert(Array.isArray(result.topics)); @@ -226,7 +222,14 @@ describe('Categories', function () { }); it('should load more topics', function (done) { - socketCategories.loadMore({ uid: posterUid }, { cid: categoryObj.cid, after: 0, author: 'poster', tag: 'nodebb' }, function (err, data) { + socketCategories.loadMore({ uid: posterUid }, { + cid: categoryObj.cid, + after: 0, + query: { + author: 'poster', + tag: 'nodebb', + }, + }, function (err, data) { assert.ifError(err); assert(Array.isArray(data.topics)); assert.equal(data.topics[0].user.username, 'poster'); @@ -244,7 +247,7 @@ describe('Categories', function () { }); }); - it('should load page count', function (done) { + it('should load topic count', function (done) { socketCategories.getTopicCount({ uid: posterUid }, categoryObj.cid, function (err, topicCount) { assert.ifError(err); assert.equal(topicCount, 2); @@ -680,4 +683,31 @@ describe('Categories', function () { }); }); }); + + + describe('getTopicIds', function () { + var plugins = require('../src/plugins'); + it('should get topic ids with filter', function (done) { + function method(data, callback) { + data.tids = [1, 2, 3]; + callback(null, data); + } + + plugins.registerHook('my-test-plugin', { + hook: 'filter:categories.getTopicIds', + method: method, + }); + + Categories.getTopicIds({ + cid: categoryObj.cid, + start: 0, + stop: 19, + }, function (err, tids) { + assert.ifError(err); + assert.deepEqual(tids, [1, 2, 3]); + plugins.unregisterHook('my-test-plugin', 'filter:categories.getTopicIds', method); + done(); + }); + }); + }); }); From deecf044540692edac627dfb7f4f413938994073 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Wed, 7 Jun 2017 14:21:03 -0400 Subject: [PATCH 03/96] add filter:search.filterAndSort --- src/search.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/search.js b/src/search.js index 3ed7f4ef35..6fe103015c 100644 --- a/src/search.js +++ b/src/search.js @@ -122,7 +122,10 @@ function filterAndSort(pids, data, callback) { sortPosts(posts, data); - pids = posts.map(function (post) { + plugins.fireHook('filter:search.filterAndSort', { pids: pids, posts: posts, data: data }, next); + }, + function (result, next) { + pids = result.posts.map(function (post) { return post && post.pid; }); From 982184740d61d9caad10af9b2f0e9168323070c1 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Thu, 8 Jun 2017 12:39:12 -0400 Subject: [PATCH 04/96] small refactor of category controller --- src/controllers/category.js | 40 ++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/src/controllers/category.js b/src/controllers/category.js index 495b1fc9f2..a2e3ef3141 100644 --- a/src/controllers/category.js +++ b/src/controllers/category.js @@ -27,6 +27,8 @@ categoryController.get = function (req, res, callback) { return callback(); } + var topicIndex = utils.isNumber(req.params.topic_index) ? parseInt(req.params.topic_index, 10) - 1 : 0; + async.waterfall([ function (next) { async.parallel({ @@ -57,7 +59,7 @@ categoryController.get = function (req, res, callback) { } settings = results.userSettings; - var topicIndex = utils.isNumber(req.params.topic_index) ? parseInt(req.params.topic_index, 10) - 1 : 0; + var topicCount = parseInt(results.categoryData.topic_count, 10); pageCount = Math.max(1, Math.ceil(topicCount / settings.topicsPerPage)); @@ -77,30 +79,22 @@ categoryController.get = function (req, res, callback) { topicIndex = 0; } - var sort = req.query.sort || settings.categoryTopicSort; + user.getUidByUserslug(req.query.author, next); + }, + function (targetUid, next) { var start = ((currentPage - 1) * settings.topicsPerPage) + topicIndex; var stop = start + settings.topicsPerPage - 1; - - async.waterfall([ - function (next) { - user.getUidByUserslug(req.query.author, next); - }, - function (targetUid, next) { - var payload = { - uid: req.uid, - cid: cid, - start: start, - stop: stop, - sort: sort, - settings: settings, - query: req.query, - tag: req.query.tag, - targetUid: targetUid, - }; - - categories.getCategoryById(payload, next); - }, - ], next); + categories.getCategoryById({ + uid: req.uid, + cid: cid, + start: start, + stop: stop, + sort: req.query.sort || settings.categoryTopicSort, + settings: settings, + query: req.query, + tag: req.query.tag, + targetUid: targetUid, + }, next); }, function (categoryData, next) { categories.modifyTopicsByPrivilege(categoryData.topics, userPrivileges); From f6ba79287bccd9bfade5d72711d414b1995584b7 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Thu, 8 Jun 2017 14:12:07 -0400 Subject: [PATCH 05/96] get full topic data --- src/search.js | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/search.js b/src/search.js index 6fe103015c..4ad633438f 100644 --- a/src/search.js +++ b/src/search.js @@ -135,25 +135,12 @@ function filterAndSort(pids, data, callback) { } function getMatchedPosts(pids, data, callback) { - var postFields = ['pid', 'tid', 'timestamp', 'deleted']; - var topicFields = ['deleted']; + var postFields = ['pid', 'uid', 'tid', 'timestamp', 'deleted']; var categoryFields = []; - if (data.replies) { - topicFields.push('postcount'); - } - if (data.sortBy && data.sortBy !== 'relevance') { - if (data.sortBy.startsWith('category')) { - topicFields.push('cid'); - } else if (data.sortBy.startsWith('topic.')) { - topicFields.push(data.sortBy.split('.')[1]); - } else if (data.sortBy.startsWith('user.')) { - postFields.push('uid'); - } else if (data.sortBy.startsWith('category.')) { + if (data.sortBy.startsWith('category.')) { categoryFields.push(data.sortBy.split('.')[1]); - } else if (data.sortBy.startsWith('teaser')) { - topicFields.push('teaserPid'); } } @@ -163,7 +150,6 @@ function getMatchedPosts(pids, data, callback) { var keys = pids.map(function (pid) { return 'post:' + pid; }); - db.getObjectsFields(keys, postFields, next); }, function (_posts, next) { @@ -189,14 +175,14 @@ function getMatchedPosts(pids, data, callback) { var topicKeys = posts.map(function (post) { return 'topic:' + post.tid; }); - db.getObjectsFields(topicKeys, topicFields, next); + db.getObjects(topicKeys, next); }, function (_topics, next) { topicsData = _topics; async.parallel({ teasers: function (next) { - if (topicFields.indexOf('teaserPid') !== -1) { + if (data.sortBy.startsWith('teaser')) { var teaserKeys = topicsData.map(function (topic) { return 'post:' + topic.teaserPid; }); From bcf2156028e3bc21a57a84d88370a4caaca4a1fb Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Thu, 8 Jun 2017 14:29:14 -0400 Subject: [PATCH 06/96] check sortBy --- src/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.js b/src/search.js index 4ad633438f..6e194c37be 100644 --- a/src/search.js +++ b/src/search.js @@ -182,7 +182,7 @@ function getMatchedPosts(pids, data, callback) { async.parallel({ teasers: function (next) { - if (data.sortBy.startsWith('teaser')) { + if (data.sortBy && data.sortBy.startsWith('teaser')) { var teaserKeys = topicsData.map(function (topic) { return 'post:' + topic.teaserPid; }); From e0dc47f88338c617207aa063dde1cb721a165001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Mon, 26 Jun 2017 16:51:45 -0400 Subject: [PATCH 07/96] closes #5779 --- src/categories/delete.js | 2 +- src/categories/topics.js | 19 ++++++++++++++++--- src/topics/tools.js | 11 ++++------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/categories/delete.js b/src/categories/delete.js index a4215b5ff2..87ae9813d9 100644 --- a/src/categories/delete.js +++ b/src/categories/delete.js @@ -19,7 +19,7 @@ module.exports = function (Categories) { }, { alwaysStartAt: 0 }, next); }, function (next) { - Categories.getPinnedTids('cid:' + cid + ':tids:pinned', 0, -1, next); + db.getSortedSetRevRange('cid:' + cid + ':tids:pinned', 0, -1, next); }, function (pinnedTids, next) { async.eachLimit(pinnedTids, 10, function (tid, next) { diff --git a/src/categories/topics.js b/src/categories/topics.js index bedf6e81c7..af6cd9c0bd 100644 --- a/src/categories/topics.js +++ b/src/categories/topics.js @@ -1,6 +1,7 @@ 'use strict'; var async = require('async'); +var _ = require('lodash'); var db = require('../database'); var topics = require('../topics'); @@ -41,7 +42,10 @@ module.exports = function (Categories) { async.waterfall([ function (next) { - Categories.getPinnedTids(data.cid, 0, -1, next); + var dataForPinned = _.cloneDeep(data); + dataForPinned.start = 0; + dataForPinned.stop = -1; + Categories.getPinnedTids(dataForPinned, next); }, function (_pinnedTids, next) { var totalPinnedCount = _pinnedTids.length; @@ -148,8 +152,17 @@ module.exports = function (Categories) { db.getSortedSetRange(['cid:' + cid + ':tids:pinned', 'cid:' + cid + ':tids'], start, stop, callback); }; - Categories.getPinnedTids = function (cid, start, stop, callback) { - db.getSortedSetRevRange('cid:' + cid + ':tids:pinned', start, stop, callback); + Categories.getPinnedTids = function (data, callback) { + if (plugins.hasListeners('filter:categories.getPinnedTids')) { + return plugins.fireHook('filter:categories.getPinnedTids', { + pinnedTids: [], + data: data, + }, function (err, data) { + callback(err, data && data.pinnedTids); + }); + } + + db.getSortedSetRevRange('cid:' + data.cid + ':tids:pinned', data.start, data.stop, callback); }; Categories.modifyTopicsByPrivilege = function (topics, privileges) { diff --git a/src/topics/tools.js b/src/topics/tools.js index db112e9daa..3c8835d245 100644 --- a/src/topics/tools.js +++ b/src/topics/tools.js @@ -154,16 +154,13 @@ module.exports = function (Topics) { var topicData; async.waterfall([ function (next) { - Topics.exists(tid, next); - }, - function (exists, next) { - if (!exists) { - return callback(new Error('[[error:no-topic]]')); - } - Topics.getTopicFields(tid, ['uid', 'tid', 'cid', 'lastposttime', 'postcount'], next); + Topics.getTopicData(tid, next); }, function (_topicData, next) { topicData = _topicData; + if (!topicData) { + return callback(new Error('[[error:no-topic]]')); + } privileges.categories.isAdminOrMod(_topicData.cid, uid, next); }, function (isAdminOrMod, next) { From 48907314447e11a86e1412e970dd61612b8e86f1 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Tue, 27 Jun 2017 14:34:37 -0400 Subject: [PATCH 08/96] don't error if topicsContainer is not set --- public/src/modules/topicSelect.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/public/src/modules/topicSelect.js b/public/src/modules/topicSelect.js index 185e5e36a0..3040b36e98 100644 --- a/public/src/modules/topicSelect.js +++ b/public/src/modules/topicSelect.js @@ -39,6 +39,9 @@ define('topicSelect', ['components'], function (components) { TopicSelect.getSelectedTids = function () { var tids = []; + if (!topicsContainer) { + return tids; + } topicsContainer.find('[component="category/topic"].selected').each(function () { tids.push($(this).attr('data-tid')); }); @@ -46,8 +49,10 @@ define('topicSelect', ['components'], function (components) { }; TopicSelect.unselectAll = function () { - topicsContainer.find('[component="category/topic"].selected').removeClass('selected'); - topicsContainer.find('[component="topic/select"]').toggleClass('fa-check-square-o', false).toggleClass('fa-square-o', true); + if (topicsContainer) { + topicsContainer.find('[component="category/topic"].selected').removeClass('selected'); + topicsContainer.find('[component="topic/select"]').toggleClass('fa-check-square-o', false).toggleClass('fa-square-o', true); + } }; function selectRange(clickedTid) { From 8a7950bfd52288e1e898baed37533ae7898c644f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 29 Jun 2017 14:17:29 -0400 Subject: [PATCH 09/96] add new hook to allow plugins to modify list of valid filters --- src/controllers/mods.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/controllers/mods.js b/src/controllers/mods.js index 98990e97ba..6ca2d1d7ac 100644 --- a/src/controllers/mods.js +++ b/src/controllers/mods.js @@ -6,6 +6,7 @@ var user = require('../user'); var categories = require('../categories'); var flags = require('../flags'); var analytics = require('../analytics'); +var plugins = require('../plugins'); var modsController = module.exports; modsController.flags = {}; @@ -13,6 +14,7 @@ modsController.flags = {}; modsController.flags.list = function (req, res, next) { var filters; var hasFilter; + var validFilters = ['assignee', 'state', 'reporterId', 'type', 'targetUid', 'cid', 'quick']; async.waterfall([ function (next) { async.parallel({ @@ -20,6 +22,16 @@ modsController.flags.list = function (req, res, next) { moderatedCids: async.apply(user.getModeratedCids, req.uid), }, next); }, + function (results, next) { + plugins.fireHook('filter:flags.validateFilters', { filters: validFilters }, function (err, data) { + if (err) { + return next(err); + } + + validFilters = data.filters; + next(null, results); + }); + }, function (results, next) { if (!(results.isAdminOrGlobalMod || !!results.moderatedCids.length)) { return next(new Error('[[error:no-privileges]]')); @@ -31,8 +43,8 @@ modsController.flags.list = function (req, res, next) { // Parse query string params for filters hasFilter = false; - var valid = ['assignee', 'state', 'reporterId', 'type', 'targetUid', 'cid', 'quick']; - filters = valid.reduce(function (memo, cur) { + + filters = validFilters.reduce(function (memo, cur) { if (req.query.hasOwnProperty(cur)) { memo[cur] = req.query[cur]; } From 77ec169591bd12f81a2042f192b5cf49e7d934f1 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 7 Jul 2017 15:48:01 -0400 Subject: [PATCH 10/96] added two new client-side hooks for search to allow plugins to add fields --- public/src/client/search.js | 11 ++++++++--- public/src/modules/search.js | 6 ++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/public/src/client/search.js b/public/src/client/search.js index 515f7030b5..19f66daebe 100644 --- a/public/src/client/search.js +++ b/public/src/client/search.js @@ -17,7 +17,7 @@ define('forum/search', ['search', 'autocomplete', 'storage'], function (searchMo $('#advanced-search').off('submit').on('submit', function (e) { e.preventDefault(); - searchModule.query(getSearchData(), function () { + searchModule.query(getSearchDataFromDOM(), function () { $('#search-input').val(''); }); return false; @@ -30,7 +30,7 @@ define('forum/search', ['search', 'autocomplete', 'storage'], function (searchMo fillOutForm(); }; - function getSearchData() { + function getSearchDataFromDOM() { var form = $('#advanced-search'); var searchData = { in: $('#search-in').val(), @@ -50,6 +50,11 @@ define('forum/search', ['search', 'autocomplete', 'storage'], function (searchMo searchData.showAs = form.find('#show-as-topics').is(':checked') ? 'topics' : 'posts'; } + $(window).trigger('action:search.getSearchDataFromDOM', { + form: form, + data: searchData, + }); + return searchData; } @@ -146,7 +151,7 @@ define('forum/search', ['search', 'autocomplete', 'storage'], function (searchMo function handleSavePreferences() { $('#save-preferences').on('click', function () { - storage.setItem('search-preferences', JSON.stringify(getSearchData())); + storage.setItem('search-preferences', JSON.stringify(getSearchDataFromDOMFromDOM())); app.alertSuccess('[[search:search-preferences-saved]]'); return false; }); diff --git a/public/src/modules/search.js b/public/src/modules/search.js index 5b77ab7572..d9188e10c8 100644 --- a/public/src/modules/search.js +++ b/public/src/modules/search.js @@ -74,6 +74,12 @@ define('search', ['navigator', 'translator', 'storage'], function (nav, translat if (data.showAs) { query.showAs = data.showAs; } + + $(window).trigger('action:search.createQueryString', { + query: query, + dom: data, + }); + return decodeURIComponent($.param(query)); } From 9c71da157725df02743fe191eb7cab8855817b4d Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 12 Jul 2017 15:20:30 -0400 Subject: [PATCH 11/96] sending callback with welcome email test --- src/socket.io/admin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index df169aba0e..6f1345afdd 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -252,7 +252,7 @@ SocketAdmin.email.test = function (socket, data, callback) { case 'welcome': userEmail.sendValidationEmail(socket.uid, { force: 1, - }); + }, callback); break; default: From 020d3acfe9525cd0e8c6d00be3fd97becfef2836 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 12 Jul 2017 15:36:15 -0400 Subject: [PATCH 12/96] WIP welcome email --- public/images/emails/emailconfirm.png | Bin 0 -> 4667 bytes public/images/emails/trianglebackground.svg | 27 ++ src/views/emails/welcome.tpl | 280 +++++++++++++++++++- 3 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 public/images/emails/emailconfirm.png create mode 100644 public/images/emails/trianglebackground.svg diff --git a/public/images/emails/emailconfirm.png b/public/images/emails/emailconfirm.png new file mode 100644 index 0000000000000000000000000000000000000000..d066015bd9dd61bc3316b2e32d161caa0eb11a51 GIT binary patch literal 4667 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 + + + + + + + + + + + + + + + diff --git a/src/views/emails/welcome.tpl b/src/views/emails/welcome.tpl index c7a78c9056..f39ba65fd1 100644 --- a/src/views/emails/welcome.tpl +++ b/src/views/emails/welcome.tpl @@ -10,4 +10,282 @@ [[email:welcome.cta]] - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ [[email:welcome.text1, {site_title}]] +
+ + + + + + + + + + +
+ +
+ + +
+ + \ No newline at end of file From 9b813af56d801cb67993c2fc53aafd5b5b5dd65d Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 12 Jul 2017 15:58:52 -0400 Subject: [PATCH 13/96] png instead of svg --- public/images/emails/trianglebackground.svg | 27 ------------------ public/images/emails/triangularbackground.png | Bin 0 -> 47961 bytes 2 files changed, 27 deletions(-) delete mode 100644 public/images/emails/trianglebackground.svg create mode 100644 public/images/emails/triangularbackground.png diff --git a/public/images/emails/trianglebackground.svg b/public/images/emails/trianglebackground.svg deleted file mode 100644 index bb66aae204..0000000000 --- a/public/images/emails/trianglebackground.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/public/images/emails/triangularbackground.png b/public/images/emails/triangularbackground.png new file mode 100644 index 0000000000000000000000000000000000000000..c47ad51810569a77f7504200d59e4ecd7cf52008 GIT binary patch literal 47961 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%0D2gF11j#@ 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 Date: Wed, 12 Jul 2017 23:29:56 -0600 Subject: [PATCH 14/96] Override winston to use console.log instead of stdout --- app.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app.js b/app.js index 7a0b7bc2a5..d3b4af0697 100644 --- a/app.js +++ b/app.js @@ -37,6 +37,7 @@ var winston = require('winston'); var path = require('path'); var pkg = require('./package.json'); var file = require('./src/file'); +var debug = require('./src/meta/debugParams')().execArgv.length; global.env = process.env.NODE_ENV || 'production'; @@ -52,6 +53,22 @@ winston.add(winston.transports.Console, { stringify: (!!nconf.get('json-logging')), }); +if (debug) { + var winstonCommon = require('winston/lib/winston/common'); + // Override to use real console.log etc for VSCode debugger + winston.transports.Console.prototype.log = function (level, message, meta, callback) { + const output = winstonCommon.log(Object.assign({}, this, { + level, + message, + meta, + })); + + console[level in console ? level : 'log'](output); + + setImmediate(callback, null, true); + }; +} + // Alternate configuration file support var configFile = path.join(__dirname, '/config.json'); From ee5895f5344d600c780a4c07c77ef195887ac471 Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Wed, 12 Jul 2017 23:31:29 -0600 Subject: [PATCH 15/96] Fix #5488 Support scoped plugin npm packages --- public/src/admin/extend/plugins.js | 4 +- src/plugins.js | 84 +++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 26 deletions(-) diff --git a/public/src/admin/extend/plugins.js b/public/src/admin/extend/plugins.js index 9622b4fbc0..dbc722aa2a 100644 --- a/public/src/admin/extend/plugins.js +++ b/public/src/admin/extend/plugins.js @@ -20,7 +20,7 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t pluginsList.on('click', 'button[data-action="toggleActive"]', function () { var pluginEl = $(this).parents('li'); pluginID = pluginEl.attr('data-plugin-id'); - var btn = $('#' + pluginID + ' [data-action="toggleActive"]'); + var btn = $('[id="' + pluginID + '"] [data-action="toggleActive"]'); socket.emit('admin.plugins.toggleActive', pluginID, function (err, status) { if (err) { return app.alertError(err); @@ -30,7 +30,7 @@ define('admin/extend/plugins', ['jqueryui', 'translator'], function (jqueryui, t btn.toggleClass('btn-warning', status.active).toggleClass('btn-success', !status.active); // clone it to active plugins tab - if (status.active && !$('#active #' + pluginID).length) { + if (status.active && !$('#active [id="' + pluginID + '"]').length) { $('#active ul').prepend(pluginEl.clone(true)); } diff --git a/src/plugins.js b/src/plugins.js index 7c758c517a..de328887eb 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -298,38 +298,74 @@ Plugins.normalise = function (apiReturn, callback) { }; Plugins.showInstalled = function (callback) { - var npmPluginPath = path.join(__dirname, '../node_modules'); + var nodeModulesPath = path.join(__dirname, '../node_modules'); + var pluginNamePattern = /^(@.*?\/)?nodebb-(theme|plugin|widget|rewards)-.*$/; async.waterfall([ - async.apply(fs.readdir, npmPluginPath), - + function (next) { + fs.readdir(nodeModulesPath, next); + }, function (dirs, next) { - dirs = dirs.filter(function (dir) { - return dir.startsWith('nodebb-plugin-') || - dir.startsWith('nodebb-widget-') || - dir.startsWith('nodebb-rewards-') || - dir.startsWith('nodebb-theme-'); - }).map(function (dir) { - return path.join(npmPluginPath, dir); - }); + var pluginPaths = []; - async.filter(dirs, function (dir, callback) { - fs.stat(dir, function (err, stats) { - if (err) { - if (err.code === 'ENOENT') { - return callback(null, false); - } - return callback(err); - } - callback(null, stats.isDirectory()); - }); - }, next); + async.each(dirs, function (dirname, next) { + var dirPath = path.join(nodeModulesPath, dirname); + + async.waterfall([ + function (cb) { + fs.stat(dirPath, function (err, stats) { + if (err && err.code !== 'ENOENT') { + return next(err); + } + if (err || !stats.isDirectory()) { + return next(); + } + + if (pluginNamePattern.test(dirname)) { + pluginPaths.push(dirname); + return next(); + } + + if (dirname[0] !== '@') { + return next(); + } + fs.readdir(dirPath, cb); + }); + }, + function (subdirs, cb) { + async.each(subdirs, function (subdir, next) { + if (!pluginNamePattern.test(subdir)) { + return next(); + } + + var subdirPath = path.join(dirPath, subdir); + fs.stat(subdirPath, function (err, stats) { + if (err && err.code !== 'ENOENT') { + return next(err); + } + + if (err || !stats.isDirectory()) { + return next(); + } + + pluginPaths.push(dirname + '/' + subdir); + next(); + }); + }, cb); + }, + ], next); + }, function (err) { + next(err, pluginPaths); + }); }, - function (files, next) { + function (dirs, next) { + dirs = dirs.map(function (dir) { + return path.join(nodeModulesPath, dir); + }); var plugins = []; - async.each(files, function (file, next) { + async.each(dirs, function (file, next) { async.waterfall([ function (next) { Plugins.loadPluginInfo(file, next); From 15d368c6b9779068dc108489b7d9770e676cddc5 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 13 Jul 2017 10:43:27 -0400 Subject: [PATCH 16/96] more changes to welcome.tpl --- src/views/emails/welcome.tpl | 64 +++--------------------------------- 1 file changed, 4 insertions(+), 60 deletions(-) diff --git a/src/views/emails/welcome.tpl b/src/views/emails/welcome.tpl index f39ba65fd1..3ac45b06cd 100644 --- a/src/views/emails/welcome.tpl +++ b/src/views/emails/welcome.tpl @@ -1,21 +1,3 @@ -

[[email:greeting_with_name, {username}]],

- -

- [[email:welcome.text1, {site_title}]] -

- -

[[email:welcome.text2]]

- -
- [[email:welcome.cta]] -
- - - - - - - @@ -191,23 +173,13 @@ - - - - - -
- alt_text -
- - - @@ -239,8 +211,8 @@
- alt_text + + alt_text
-

Praesent in felis ut velit pretium lobortis rhoncus ut erat.

-

Maecenas sed ante pellentesque, posuere leo id, eleifend dolor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent laoreet malesuada cursus. Maecenas scelerisque congue eros eu posuere. Praesent in felis ut velit pretium lobortis rhoncus ut erat.

+

[[email:closing]]

+

{site_title}

@@ -258,34 +230,6 @@ - - - - - -
- -
- - \ No newline at end of file From 50e37713bfc53d6ea6d0c4efefe20cc03d0e0994 Mon Sep 17 00:00:00 2001 From: Baris Usakli Date: Tue, 11 Jul 2017 16:18:20 -0400 Subject: [PATCH 17/96] composer-default --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6592fe6b18..fbe4ad5246 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "morgan": "^1.3.2", "mousetrap": "^1.5.3", "nconf": "~0.8.2", - "nodebb-plugin-composer-default": "5.0.0", + "nodebb-plugin-composer-default": "5.0.1", "nodebb-plugin-dbsearch": "2.0.4", "nodebb-plugin-emoji-extended": "1.1.1", "nodebb-plugin-emoji-one": "1.2.1", From a2627d20667353d55a7dbf77836a8907858b1670 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 13 Jul 2017 11:30:44 -0400 Subject: [PATCH 18/96] added default payload to emails, and adding nodebb logo for email header --- public/images/emails/nodebb.png | Bin 0 -> 6285 bytes src/emailer.js | 10 ++++++++++ src/messaging/notifications.js | 2 -- src/socket.io/admin.js | 2 -- src/socket.io/user.js | 1 - src/socket.io/user/ban.js | 1 - src/topics/follow.js | 1 - src/user/approval.js | 1 - src/user/digest.js | 2 -- src/user/email.js | 1 - src/user/reset.js | 1 - src/views/emails/welcome.tpl | 14 ++++++++++++-- 12 files changed, 22 insertions(+), 14 deletions(-) create mode 100644 public/images/emails/nodebb.png diff --git a/public/images/emails/nodebb.png b/public/images/emails/nodebb.png new file mode 100644 index 0000000000000000000000000000000000000000..11ac9507adaccf6d55a7267f4648adc2cfca9dbc GIT binary patch literal 6285 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 literal 0 HcmV?d00001 diff --git a/src/emailer.js b/src/emailer.js index 38d68102c1..5120ef9caf 100644 --- a/src/emailer.js +++ b/src/emailer.js @@ -25,10 +25,17 @@ var fallbackTransport; var Emailer = module.exports; +Emailer._defaultPayload = {}; Emailer.registerApp = function (expressApp) { app = expressApp; + Emailer._defaultPayload = { + url: nconf.get('url'), + site_title: meta.config.title || 'NodeBB', + 'brand:logo': nconf.get('url') + meta.config['brand:logo'], + }; + // Enable Gmail transport if enabled in ACP if (parseInt(meta.config['email:GmailTransport:enabled'], 10) === 1) { transports.gmail = nodemailer.createTransport(smtpTransport({ @@ -55,6 +62,9 @@ Emailer.send = function (template, uid, params, callback) { return callback(); } + // Combined passed-in payload with default values + params = Object.assign({}, Emailer._defaultPayload, params); + async.waterfall([ function (next) { async.parallel({ diff --git a/src/messaging/notifications.js b/src/messaging/notifications.js index 5d433b2c33..12640def03 100644 --- a/src/messaging/notifications.js +++ b/src/messaging/notifications.js @@ -124,8 +124,6 @@ module.exports = function (Messaging) { subject: '[[email:notif.chat.subject, ' + messageObj.fromUser.username + ']]', summary: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]', message: messageObj, - site_title: meta.config.title || 'NodeBB', - url: nconf.get('url'), roomId: messageObj.roomId, username: userData.username, userslug: userData.userslug, diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index 6f1345afdd..304fdd831c 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -228,8 +228,6 @@ SocketAdmin.email.test = function (socket, data, callback) { var site_title = meta.config.title || 'NodeBB'; var payload = { subject: '[' + site_title + '] Test Email', - site_title: site_title, - url: nconf.get('url'), }; switch (data.template) { diff --git a/src/socket.io/user.js b/src/socket.io/user.js index d59fad3c58..1ed67276c4 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -128,7 +128,6 @@ SocketUser.reset.commit = function (socket, data, callback) { emailer.send('reset_notify', uid, { username: username, date: parsedDate, - site_title: meta.config.title || 'NodeBB', subject: '[[email:reset.notify.subject]]', }); diff --git a/src/socket.io/user/ban.js b/src/socket.io/user/ban.js index d6cfbd6f68..a61a9b83ee 100644 --- a/src/socket.io/user/ban.js +++ b/src/socket.io/user/ban.js @@ -107,7 +107,6 @@ module.exports = function (SocketUser) { var siteTitle = meta.config.title || 'NodeBB'; var data = { subject: '[[email:banned.subject, ' + siteTitle + ']]', - site_title: siteTitle, username: username, until: until ? utils.toISOString(until) : false, reason: reason, diff --git a/src/topics/follow.js b/src/topics/follow.js index 89db6b3d13..62ee424eea 100644 --- a/src/topics/follow.js +++ b/src/topics/follow.js @@ -259,7 +259,6 @@ module.exports = function (Topics) { subject: '[' + (meta.config.title || 'NodeBB') + '] ' + title, intro: '[[notifications:user_posted_to, ' + postData.user.username + ', ' + titleEscaped + ']]', postBody: postData.content.replace(/"\/\//g, '"https://'), - site_title: meta.config.title || 'NodeBB', username: data.userData.username, userslug: data.userData.userslug, url: nconf.get('url') + '/topic/' + postData.topic.tid, diff --git a/src/user/approval.js b/src/user/approval.js index d04686a7b0..4beeab6806 100644 --- a/src/user/approval.js +++ b/src/user/approval.js @@ -89,7 +89,6 @@ module.exports = function (User) { var title = meta.config.title || meta.config.browserTitle || 'NodeBB'; translator.translate('[[email:welcome-to, ' + title + ']]', meta.config.defaultLang, function (subject) { var data = { - site_title: title, username: username, subject: subject, template: 'registration_accepted', diff --git a/src/user/digest.js b/src/user/digest.js index 61b727de3a..ffd4f9031e 100644 --- a/src/user/digest.js +++ b/src/user/digest.js @@ -136,8 +136,6 @@ Digest.send = function (data, callback) { subject: '[' + meta.config.title + '] [[email:digest.subject, ' + (now.getFullYear() + '/' + (now.getMonth() + 1) + '/' + now.getDate()) + ']]', username: userObj.username, userslug: userObj.userslug, - url: nconf.get('url'), - site_title: meta.config.title || meta.config.browserTitle || 'NodeBB', notifications: notifications, recent: data.topics, interval: data.interval, diff --git a/src/user/email.js b/src/user/email.js index 734e247eb1..9c61211d9a 100644 --- a/src/user/email.js +++ b/src/user/email.js @@ -102,7 +102,6 @@ UserEmail.sendValidationEmail = function (uid, options, callback) { var title = meta.config.title || meta.config.browserTitle || 'NodeBB'; translator.translate('[[email:welcome-to, ' + title + ']]', meta.config.defaultLang, function (subject) { var data = { - site_title: title, username: username, confirm_link: confirm_link, confirm_code: confirm_code, diff --git a/src/user/reset.js b/src/user/reset.js index 438d629225..2aaa1d76bb 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -85,7 +85,6 @@ UserReset.send = function (email, callback) { function (subject, code, next) { var reset_link = nconf.get('url') + '/reset/' + code; emailer.send('reset', uid, { - site_title: (meta.config.title || 'NodeBB'), reset_link: reset_link, subject: subject, template: 'reset', diff --git a/src/views/emails/welcome.tpl b/src/views/emails/welcome.tpl index 3ac45b06cd..6f126a7754 100644 --- a/src/views/emails/welcome.tpl +++ b/src/views/emails/welcome.tpl @@ -173,12 +173,22 @@ + + + + + +
+ alt_text +
+ + - @@ -186,7 +196,7 @@ - - @@ -233,6 +233,18 @@
+ alt_text
+ From 6c768030cc6a495c883b7d334c0731eb281cb8d0 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 13 Jul 2017 12:39:58 -0400 Subject: [PATCH 21/96] using variable for urls again, welcome.tpl done I think --- src/views/emails/welcome.tpl | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/views/emails/welcome.tpl b/src/views/emails/welcome.tpl index ab406f0d9b..74eacbd13c 100644 --- a/src/views/emails/welcome.tpl +++ b/src/views/emails/welcome.tpl @@ -176,8 +176,8 @@
From 2eecf43eaeb42ca965cc68c86bc93652e049d733 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 13 Jul 2017 11:51:48 -0400 Subject: [PATCH 19/96] updated logo image --- public/images/emails/nodebb.png | Bin 6285 -> 6792 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/images/emails/nodebb.png b/public/images/emails/nodebb.png index 11ac9507adaccf6d55a7267f4648adc2cfca9dbc..be8ee73f7832bc0bb061289f5d971c75d7a22381 100644 GIT binary patch literal 6792 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 From 10d23f544752ebac7d2a8fba1f00399bd6199e74 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 13 Jul 2017 12:21:24 -0400 Subject: [PATCH 20/96] resized logo again --- public/images/emails/nodebb.png | Bin 6792 -> 4205 bytes src/views/emails/welcome.tpl | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/images/emails/nodebb.png b/public/images/emails/nodebb.png index be8ee73f7832bc0bb061289f5d971c75d7a22381..9cfe1cd70cdfab7ffbf1d5dde0ba6d9a3601b4ef 100644 GIT binary patch literal 4205 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 -
- alt_text + + {site_title}
@@ -189,7 +189,7 @@
- alt_text + alt_text
-
- {site_title} + + {site_title}
@@ -188,8 +188,8 @@
- alt_text + +
+ + + + + +
+

+   +

+
+ + + + + + +
+

+   +

+
+ + + + + + + + + \ No newline at end of file diff --git a/src/views/emails/partials/header.tpl b/src/views/emails/partials/header.tpl new file mode 100644 index 0000000000..fd94ab4294 --- /dev/null +++ b/src/views/emails/partials/header.tpl @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +