diff --git a/public/language/en-GB/unread.json b/public/language/en-GB/unread.json index 4a449a53f5..74634f9080 100644 --- a/public/language/en-GB/unread.json +++ b/public/language/en-GB/unread.json @@ -9,5 +9,6 @@ "topics_marked_as_read.success": "Topics marked as read!", "all-topics": "All Topics", "new-topics": "New Topics", - "watched-topics": "Watched Topics" + "watched-topics": "Watched Topics", + "unreplied-topics": "Unreplied Topics" } \ No newline at end of file diff --git a/src/controllers/helpers.js b/src/controllers/helpers.js index ee0ba75482..70de194323 100644 --- a/src/controllers/helpers.js +++ b/src/controllers/helpers.js @@ -32,6 +32,32 @@ helpers.noScriptErrors = function (req, res, error, httpStatus) { }); }; +helpers.validFilters = { '': true, new: true, watched: true, unreplied: true }; + +helpers.buildFilters = function (url, filter) { + return [{ + name: '[[unread:all-topics]]', + url: url, + selected: filter === '', + filter: '', + }, { + name: '[[unread:new-topics]]', + url: url + '/new', + selected: filter === 'new', + filter: 'new', + }, { + name: '[[unread:watched-topics]]', + url: url + '/watched', + selected: filter === 'watched', + filter: 'watched', + }, { + name: '[[unread:unreplied-topics]]', + url: url + '/unreplied', + selected: filter === 'unreplied', + filter: 'unreplied', + }]; +}; + helpers.notAllowed = function (req, res, error) { plugins.fireHook('filter:helpers.notAllowed', { req: req, diff --git a/src/controllers/popular.js b/src/controllers/popular.js index 21c07224c1..99af5baf19 100644 --- a/src/controllers/popular.js +++ b/src/controllers/popular.js @@ -1,12 +1,13 @@ 'use strict'; +var async = require('async'); var nconf = require('nconf'); var topics = require('../topics'); var meta = require('../meta'); var helpers = require('./helpers'); -var popularController = {}; +var popularController = module.exports; var anonCache = {}; var lastUpdateTime = 0; @@ -38,36 +39,35 @@ popularController.get = function (req, res, next) { } } - topics.getPopular(term, req.uid, meta.config.topicsPerList, function (err, topics) { - if (err) { - return next(err); - } - - var data = { - topics: topics, - 'feeds:disableRSS': parseInt(meta.config['feeds:disableRSS'], 10) === 1, - rssFeedUrl: nconf.get('relative_path') + '/popular/' + (req.params.term || 'daily') + '.rss', - title: '[[pages:popular-' + term + ']]', - term: term, - }; - - if (req.path.startsWith('/api/popular') || req.path.startsWith('/popular')) { - var breadcrumbs = [{ text: termToBreadcrumb[term] }]; - - if (req.params.term) { - breadcrumbs.unshift({ text: '[[global:header.popular]]', url: '/popular' }); + async.waterfall([ + function (next) { + topics.getPopular(term, req.uid, meta.config.topicsPerList, next); + }, + function (topics) { + var data = { + topics: topics, + 'feeds:disableRSS': parseInt(meta.config['feeds:disableRSS'], 10) === 1, + rssFeedUrl: nconf.get('relative_path') + '/popular/' + (req.params.term || 'daily') + '.rss', + title: '[[pages:popular-' + term + ']]', + term: term, + }; + + if (req.path.startsWith('/api/popular') || req.path.startsWith('/popular')) { + var breadcrumbs = [{ text: termToBreadcrumb[term] }]; + + if (req.params.term) { + breadcrumbs.unshift({ text: '[[global:header.popular]]', url: '/popular' }); + } + + data.breadcrumbs = helpers.buildBreadcrumbs(breadcrumbs); } - data.breadcrumbs = helpers.buildBreadcrumbs(breadcrumbs); - } - - if (!req.uid) { - anonCache[term] = data; - lastUpdateTime = Date.now(); - } + if (!req.uid) { + anonCache[term] = data; + lastUpdateTime = Date.now(); + } - res.render('popular', data); - }); + res.render('popular', data); + }, + ], next); }; - -module.exports = popularController; diff --git a/src/controllers/recent.js b/src/controllers/recent.js index 7d95c2db2b..3bb337d2f0 100644 --- a/src/controllers/recent.js +++ b/src/controllers/recent.js @@ -13,8 +13,6 @@ var pagination = require('../pagination'); var recentController = module.exports; -var validFilter = { '': true, new: true, watched: true }; - recentController.get = function (req, res, next) { var page = parseInt(req.query.page, 10) || 1; var stop = 0; @@ -23,7 +21,8 @@ recentController.get = function (req, res, next) { var filter = req.params.filter || ''; var categoryData; var rssToken; - if (!validFilter[filter]) { + + if (!helpers.validFilters[filter]) { return next(); } @@ -62,22 +61,7 @@ recentController.get = function (req, res, next) { data.rssFeedUrl += '?uid=' + req.uid + '&token=' + rssToken; } data.title = '[[pages:recent]]'; - data.filters = [{ - name: '[[unread:all-topics]]', - url: 'recent', - selected: filter === '', - filter: '', - }, { - name: '[[unread:new-topics]]', - url: 'recent/new', - selected: filter === 'new', - filter: 'new', - }, { - name: '[[unread:watched-topics]]', - url: 'recent/watched', - selected: filter === 'watched', - filter: 'watched', - }]; + data.filters = helpers.buildFilters('recent', filter); data.selectedFilter = data.filters.find(function (filter) { return filter && filter.selected; diff --git a/src/controllers/unread.js b/src/controllers/unread.js index 9308e87251..a3ee68192d 100644 --- a/src/controllers/unread.js +++ b/src/controllers/unread.js @@ -13,8 +13,6 @@ var helpers = require('./helpers'); var unreadController = module.exports; -var validFilter = { '': true, new: true, watched: true }; - unreadController.get = function (req, res, next) { var page = parseInt(req.query.page, 10) || 1; var results; @@ -24,7 +22,7 @@ unreadController.get = function (req, res, next) { async.waterfall([ function (next) { - plugins.fireHook('filter:unread.getValidFilters', { filters: validFilter }, next); + plugins.fireHook('filter:unread.getValidFilters', { filters: Object.assign({}, helpers.validFilters) }, next); }, function (data, _next) { if (!data.filters[filter]) { @@ -72,22 +70,7 @@ unreadController.get = function (req, res, next) { } data.title = '[[pages:unread]]'; - data.filters = [{ - name: '[[unread:all-topics]]', - url: 'unread', - selected: filter === '', - filter: '', - }, { - name: '[[unread:new-topics]]', - url: 'unread/new', - selected: filter === 'new', - filter: 'new', - }, { - name: '[[unread:watched-topics]]', - url: 'unread/watched', - selected: filter === 'watched', - filter: 'watched', - }]; + data.filters = helpers.buildFilters('unread', filter); data.selectedFilter = data.filters.find(function (filter) { return filter && filter.selected; @@ -105,10 +88,10 @@ unreadController.unreadTotal = function (req, res, next) { async.waterfall([ function (next) { - plugins.fireHook('filter:unread.getValidFilters', { filters: validFilter }, next); + plugins.fireHook('filter:unread.getValidFilters', { filters: Object.assign({}, helpers.validFilters) }, next); }, function (data, _next) { - if (!validFilter[filter]) { + if (!data.filters[filter]) { return next(); } topics.getTotalUnread(req.uid, filter, _next); diff --git a/src/topics/recent.js b/src/topics/recent.js index 7242f6bb06..c5dce9209f 100644 --- a/src/topics/recent.js +++ b/src/topics/recent.js @@ -61,6 +61,8 @@ module.exports = function (Topics) { Topics.filterWatchedTids(tids, uid, next); } else if (filter === 'new') { Topics.filterNewTids(tids, uid, next); + } else if (filter === 'unreplied') { + Topics.filterUnrepliedTids(tids, next); } else { Topics.filterNotIgnoredTids(tids, uid, next); } diff --git a/src/topics/unread.js b/src/topics/unread.js index 4a46e4c0c9..6abad117ef 100644 --- a/src/topics/unread.js +++ b/src/topics/unread.js @@ -125,6 +125,8 @@ module.exports = function (Topics) { if (params.filter === 'watched') { Topics.filterWatchedTids(tids, uid, next); + } else if (params.filter === 'unreplied') { + Topics.filterUnrepliedTids(tids, next); } else { next(null, tids); } @@ -390,4 +392,18 @@ module.exports = function (Topics) { }, ], callback); }; + + Topics.filterUnrepliedTids = function (tids, callback) { + async.waterfall([ + function (next) { + db.sortedSetScores('topics:posts', tids, next); + }, + function (scores, next) { + tids = tids.filter(function (tid, index) { + return tid && scores[index] <= 1; + }); + next(null, tids); + }, + ], callback); + }; };