mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-01 19:46:01 +01:00
unread/recent changes closes #4774
This commit is contained in:
@@ -63,8 +63,8 @@
|
|||||||
"nodebb-plugin-spam-be-gone": "0.4.10",
|
"nodebb-plugin-spam-be-gone": "0.4.10",
|
||||||
"nodebb-rewards-essentials": "0.0.9",
|
"nodebb-rewards-essentials": "0.0.9",
|
||||||
"nodebb-theme-lavender": "3.0.15",
|
"nodebb-theme-lavender": "3.0.15",
|
||||||
"nodebb-theme-persona": "4.1.79",
|
"nodebb-theme-persona": "4.1.80",
|
||||||
"nodebb-theme-vanilla": "5.1.52",
|
"nodebb-theme-vanilla": "5.1.53",
|
||||||
"nodebb-widget-essentials": "2.0.13",
|
"nodebb-widget-essentials": "2.0.13",
|
||||||
"nodemailer": "2.6.4",
|
"nodemailer": "2.6.4",
|
||||||
"nodemailer-sendmail-transport": "1.0.0",
|
"nodemailer-sendmail-transport": "1.0.0",
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ define('forum/recent', ['forum/infinitescroll', 'components'], function (infinit
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.url === 'unread/watched') {
|
if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,11 +69,11 @@ define('forum/recent', ['forum/infinitescroll', 'components'], function (infinit
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.url === 'unread/new') {
|
if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'new') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.url === 'unread/watched') {
|
if (ajaxify.data.selectedFilter && ajaxify.data.selectedFilter.filter === 'watched') {
|
||||||
socket.emit('topics.isFollowed', post.tid, function (err, isFollowed) {
|
socket.emit('topics.isFollowed', post.tid, function (err, isFollowed) {
|
||||||
if (err) {
|
if (err) {
|
||||||
app.alertError(err.message);
|
app.alertError(err.message);
|
||||||
@@ -127,13 +127,13 @@ define('forum/recent', ['forum/infinitescroll', 'components'], function (infinit
|
|||||||
};
|
};
|
||||||
|
|
||||||
Recent.loadMoreTopics = function (direction) {
|
Recent.loadMoreTopics = function (direction) {
|
||||||
if(direction < 0 || !$('[component="category"]').length) {
|
if (direction < 0 || !$('[component="category"]').length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
infinitescroll.loadMore('topics.loadMoreFromSet', {
|
infinitescroll.loadMore('topics.loadMoreFromSet', {
|
||||||
after: $('[component="category"]').attr('data-nextstart'),
|
after: $('[component="category"]').attr('data-nextstart'),
|
||||||
set: $('[component="category"]').attr('data-set') ? $('[component="category"]').attr('data-set') : 'topics:recent'
|
set: $('[component="category"]').attr('data-set') ? $('[component="category"]').attr('data-set') : 'topics:recent'
|
||||||
}, function (data, done) {
|
}, function (data, done) {
|
||||||
if (data.topics && data.topics.length) {
|
if (data.topics && data.topics.length) {
|
||||||
Recent.onTopicsLoaded('recent', data.topics, false, done);
|
Recent.onTopicsLoaded('recent', data.topics, false, done);
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ var async = require('async');
|
|||||||
var validator = require('validator');
|
var validator = require('validator');
|
||||||
var winston = require('winston');
|
var winston = require('winston');
|
||||||
|
|
||||||
|
var user = require('../user');
|
||||||
|
var privileges = require('../privileges');
|
||||||
var categories = require('../categories');
|
var categories = require('../categories');
|
||||||
var plugins = require('../plugins');
|
var plugins = require('../plugins');
|
||||||
var meta = require('../meta');
|
var meta = require('../meta');
|
||||||
@@ -129,4 +131,49 @@ helpers.buildTitle = function (pageTitle) {
|
|||||||
return title;
|
return title;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
helpers.getWatchedCategories = function(uid, selectedCid, callback) {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
user.getWatchedCategories(uid, next);
|
||||||
|
},
|
||||||
|
function (cids, next) {
|
||||||
|
privileges.categories.filterCids('read', cids, uid, next);
|
||||||
|
},
|
||||||
|
function (cids, next) {
|
||||||
|
categories.getCategoriesFields(cids, ['cid', 'name', 'slug', 'icon', 'link', 'color', 'bgColor', 'parentCid'], next);
|
||||||
|
},
|
||||||
|
function (categoryData, next) {
|
||||||
|
categoryData = categoryData.filter(function (category) {
|
||||||
|
return category && !category.link;
|
||||||
|
});
|
||||||
|
|
||||||
|
var selectedCategory;
|
||||||
|
categoryData.forEach(function (category) {
|
||||||
|
category.selected = parseInt(category.cid, 10) === parseInt(selectedCid, 10);
|
||||||
|
if (category.selected) {
|
||||||
|
selectedCategory = category;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var categoriesData = [];
|
||||||
|
var tree = categories.getTree(categoryData, 0);
|
||||||
|
|
||||||
|
tree.forEach(function (category) {
|
||||||
|
recursive(category, categoriesData, '');
|
||||||
|
});
|
||||||
|
|
||||||
|
next(null, {categories: categoriesData, selectedCategory: selectedCategory});
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
function recursive(category, categoriesData, level) {
|
||||||
|
category.level = level;
|
||||||
|
categoriesData.push(category);
|
||||||
|
|
||||||
|
category.children.forEach(function (child) {
|
||||||
|
recursive(child, categoriesData, ' ' + level);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = helpers;
|
module.exports = helpers;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
var nconf = require('nconf');
|
var nconf = require('nconf');
|
||||||
|
var validator = require('validator');
|
||||||
|
|
||||||
var db = require('../database');
|
var db = require('../database');
|
||||||
var privileges = require('../privileges');
|
var privileges = require('../privileges');
|
||||||
@@ -14,12 +15,21 @@ var pagination = require('../pagination');
|
|||||||
|
|
||||||
var recentController = {};
|
var recentController = {};
|
||||||
|
|
||||||
|
var validFilter = {'': true, 'new': true, 'watched': true};
|
||||||
|
|
||||||
recentController.get = function (req, res, next) {
|
recentController.get = function (req, res, next) {
|
||||||
var page = parseInt(req.query.page, 10) || 1;
|
var page = parseInt(req.query.page, 10) || 1;
|
||||||
var pageCount = 1;
|
var pageCount = 1;
|
||||||
var stop = 0;
|
var stop = 0;
|
||||||
var topicCount = 0;
|
var topicCount = 0;
|
||||||
var settings;
|
var settings;
|
||||||
|
var cid = req.query.cid;
|
||||||
|
var filter = req.params.filter || '';
|
||||||
|
var categoryData;
|
||||||
|
|
||||||
|
if (!validFilter[filter]) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
@@ -29,12 +39,16 @@ recentController.get = function (req, res, next) {
|
|||||||
},
|
},
|
||||||
tids: function (next) {
|
tids: function (next) {
|
||||||
db.getSortedSetRevRange('topics:recent', 0, 199, next);
|
db.getSortedSetRevRange('topics:recent', 0, 199, next);
|
||||||
|
},
|
||||||
|
watchedCategories: function (next) {
|
||||||
|
helpers.getWatchedCategories(req.uid, cid, next);
|
||||||
}
|
}
|
||||||
}, next);
|
}, next);
|
||||||
},
|
},
|
||||||
function (results, next) {
|
function (results, next) {
|
||||||
settings = results.settings;
|
settings = results.settings;
|
||||||
privileges.topics.filterTids('read', results.tids, req.uid, next);
|
categoryData = results.watchedCategories;
|
||||||
|
filterTids(results.tids, req.uid, cid, categoryData.categories, filter, next);
|
||||||
},
|
},
|
||||||
function (tids, next) {
|
function (tids, next) {
|
||||||
var start = Math.max(0, (page - 1) * settings.topicsPerPage);
|
var start = Math.max(0, (page - 1) * settings.topicsPerPage);
|
||||||
@@ -53,18 +67,78 @@ recentController.get = function (req, res, next) {
|
|||||||
|
|
||||||
var data = {};
|
var data = {};
|
||||||
data.topics = topics;
|
data.topics = topics;
|
||||||
|
data.categories = categoryData.categories;
|
||||||
|
data.selectedCategory = categoryData.selectedCategory;
|
||||||
data.nextStart = stop + 1;
|
data.nextStart = stop + 1;
|
||||||
data.set = 'topics:recent';
|
data.set = 'topics:recent';
|
||||||
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
|
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
|
||||||
data.rssFeedUrl = nconf.get('relative_path') + '/recent.rss';
|
data.rssFeedUrl = nconf.get('relative_path') + '/recent.rss';
|
||||||
data.title = '[[pages:recent]]';
|
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.selectedFilter = data.filters.find(function (filter) {
|
||||||
|
return filter && filter.selected;
|
||||||
|
});
|
||||||
|
|
||||||
data.pagination = pagination.create(page, pageCount);
|
data.pagination = pagination.create(page, pageCount);
|
||||||
if (req.path.startsWith('/api/recent') || req.path.startsWith('/recent')) {
|
if (req.path.startsWith('/api/recent') || req.path.startsWith('/recent')) {
|
||||||
data.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[recent:title]]'}]);
|
data.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[recent:title]]'}]);
|
||||||
}
|
}
|
||||||
|
data.querystring = cid ? ('?cid=' + validator.escape(String(cid))) : '';
|
||||||
res.render('recent', data);
|
res.render('recent', data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function filterTids(tids, uid, cid, watchedCategories, filter, callback) {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
if (filter === 'watched') {
|
||||||
|
topics.filterWatchedTids(tids, uid, next);
|
||||||
|
} else if (filter === 'new') {
|
||||||
|
topics.filterNewTids(tids, uid, next);
|
||||||
|
} else {
|
||||||
|
topics.filterNotIgnoredTids(tids, uid, next);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function (tids, next) {
|
||||||
|
privileges.topics.filterTids('read', tids, uid, next);
|
||||||
|
},
|
||||||
|
function (tids, next) {
|
||||||
|
topics.getTopicsFields(tids, ['tid', 'cid'], next);
|
||||||
|
},
|
||||||
|
function (topicData, next) {
|
||||||
|
var watchedCids = watchedCategories.map(function (category) {
|
||||||
|
return category && parseInt(category.cid, 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
tids = topicData.filter(function (topic, index) {
|
||||||
|
if (topic) {
|
||||||
|
var topicCid = parseInt(topic.cid, 10);
|
||||||
|
return watchedCids.indexOf(topicCid) !== -1 && (!cid || parseInt(cid, 10) === topicCid);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}).map(function (topic) {
|
||||||
|
return topic.tid;
|
||||||
|
});
|
||||||
|
next(null, tids);
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = recentController;
|
module.exports = recentController;
|
||||||
@@ -5,8 +5,6 @@ var async = require('async');
|
|||||||
var querystring = require('querystring');
|
var querystring = require('querystring');
|
||||||
var validator = require('validator');
|
var validator = require('validator');
|
||||||
|
|
||||||
var categories = require('../categories');
|
|
||||||
var privileges = require('../privileges');
|
|
||||||
var pagination = require('../pagination');
|
var pagination = require('../pagination');
|
||||||
var user = require('../user');
|
var user = require('../user');
|
||||||
var topics = require('../topics');
|
var topics = require('../topics');
|
||||||
@@ -30,7 +28,7 @@ unreadController.get = function (req, res, next) {
|
|||||||
function (next) {
|
function (next) {
|
||||||
async.parallel({
|
async.parallel({
|
||||||
watchedCategories: function (next) {
|
watchedCategories: function (next) {
|
||||||
getWatchedCategories(req.uid, cid, next);
|
helpers.getWatchedCategories(req.uid, cid, next);
|
||||||
},
|
},
|
||||||
settings: function (next) {
|
settings: function (next) {
|
||||||
user.getSettings(req.uid, next);
|
user.getSettings(req.uid, next);
|
||||||
@@ -82,9 +80,9 @@ unreadController.get = function (req, res, next) {
|
|||||||
filter: 'watched'
|
filter: 'watched'
|
||||||
}];
|
}];
|
||||||
|
|
||||||
data.selectedFilter = data.filters.filter(function (filter) {
|
data.selectedFilter = data.filters.find(function (filter) {
|
||||||
return filter && filter.selected;
|
return filter && filter.selected;
|
||||||
})[0];
|
});
|
||||||
|
|
||||||
data.querystring = cid ? ('?cid=' + validator.escape(String(cid))) : '';
|
data.querystring = cid ? ('?cid=' + validator.escape(String(cid))) : '';
|
||||||
|
|
||||||
@@ -92,51 +90,6 @@ unreadController.get = function (req, res, next) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function getWatchedCategories(uid, selectedCid, callback) {
|
|
||||||
async.waterfall([
|
|
||||||
function (next) {
|
|
||||||
user.getWatchedCategories(uid, next);
|
|
||||||
},
|
|
||||||
function (cids, next) {
|
|
||||||
privileges.categories.filterCids('read', cids, uid, next);
|
|
||||||
},
|
|
||||||
function (cids, next) {
|
|
||||||
categories.getCategoriesFields(cids, ['cid', 'name', 'slug', 'icon', 'link', 'color', 'bgColor', 'parentCid'], next);
|
|
||||||
},
|
|
||||||
function (categoryData, next) {
|
|
||||||
categoryData = categoryData.filter(function (category) {
|
|
||||||
return category && !category.link;
|
|
||||||
});
|
|
||||||
|
|
||||||
var selectedCategory;
|
|
||||||
categoryData.forEach(function (category) {
|
|
||||||
category.selected = parseInt(category.cid, 10) === parseInt(selectedCid, 10);
|
|
||||||
if (category.selected) {
|
|
||||||
selectedCategory = category;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var categoriesData = [];
|
|
||||||
var tree = categories.getTree(categoryData, 0);
|
|
||||||
|
|
||||||
tree.forEach(function (category) {
|
|
||||||
recursive(category, categoriesData, '');
|
|
||||||
});
|
|
||||||
|
|
||||||
next(null, {categories: categoriesData, selectedCategory: selectedCategory});
|
|
||||||
}
|
|
||||||
], callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function recursive(category, categoriesData, level) {
|
|
||||||
category.level = level;
|
|
||||||
categoriesData.push(category);
|
|
||||||
|
|
||||||
category.children.forEach(function (child) {
|
|
||||||
recursive(child, categoriesData, ' ' + level);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
unreadController.unreadTotal = function (req, res, next) {
|
unreadController.unreadTotal = function (req, res, next) {
|
||||||
var filter = req.params.filter || '';
|
var filter = req.params.filter || '';
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ function tagRoutes(app, middleware, controllers) {
|
|||||||
function categoryRoutes(app, middleware, controllers) {
|
function categoryRoutes(app, middleware, controllers) {
|
||||||
setupPageRoute(app, '/categories', middleware, [], controllers.categories.list);
|
setupPageRoute(app, '/categories', middleware, [], controllers.categories.list);
|
||||||
setupPageRoute(app, '/popular/:term?', middleware, [], controllers.popular.get);
|
setupPageRoute(app, '/popular/:term?', middleware, [], controllers.popular.get);
|
||||||
setupPageRoute(app, '/recent', middleware, [], controllers.recent.get);
|
setupPageRoute(app, '/recent/:filter?', middleware, [], controllers.recent.get);
|
||||||
setupPageRoute(app, '/unread/:filter?', middleware, [middleware.authenticate], controllers.unread.get);
|
setupPageRoute(app, '/unread/:filter?', middleware, [middleware.authenticate], controllers.unread.get);
|
||||||
|
|
||||||
setupPageRoute(app, '/category/:category_id/:slug/:topic_index', middleware, [], controllers.category.get);
|
setupPageRoute(app, '/category/:category_id/:slug/:topic_index', middleware, [], controllers.category.get);
|
||||||
|
|||||||
@@ -159,6 +159,30 @@ module.exports = function (Topics) {
|
|||||||
], callback);
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Topics.filterWatchedTids = function (tids, uid, callback) {
|
||||||
|
db.sortedSetScores('uid:' + uid + ':followed_tids', tids, function (err, scores) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
tids = tids.filter(function (tid, index) {
|
||||||
|
return tid && !!scores[index];
|
||||||
|
});
|
||||||
|
callback(null, tids);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Topics.filterNotIgnoredTids = function (tids, uid, callback) {
|
||||||
|
db.sortedSetScores('uid:' + uid + ':ignored_tids', tids, function (err, scores) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
tids = tids.filter(function (tid, index) {
|
||||||
|
return tid && !scores[index];
|
||||||
|
});
|
||||||
|
callback(null, tids);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Topics.notifyFollowers = function (postData, exceptUid, callback) {
|
Topics.notifyFollowers = function (postData, exceptUid, callback) {
|
||||||
callback = callback || function () {};
|
callback = callback || function () {};
|
||||||
var followers;
|
var followers;
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ module.exports = function (Topics) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (filter === 'watched') {
|
if (filter === 'watched') {
|
||||||
filterWatchedTids(uid, tids, next);
|
Topics.filterWatchedTids(tids, uid, next);
|
||||||
} else {
|
} else {
|
||||||
next(null, tids);
|
next(null, tids);
|
||||||
}
|
}
|
||||||
@@ -149,17 +149,6 @@ module.exports = function (Topics) {
|
|||||||
], callback);
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
function filterWatchedTids(uid, tids, callback) {
|
|
||||||
db.sortedSetScores('uid:' + uid + ':followed_tids', tids, function (err, scores) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
tids = tids.filter(function (tid, index) {
|
|
||||||
return tid && !!scores[index];
|
|
||||||
});
|
|
||||||
callback(null, tids);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function filterTopics(uid, tids, cid, ignoredCids, filter, callback) {
|
function filterTopics(uid, tids, cid, ignoredCids, filter, callback) {
|
||||||
if (!Array.isArray(ignoredCids) || !tids.length) {
|
if (!Array.isArray(ignoredCids) || !tids.length) {
|
||||||
@@ -374,4 +363,16 @@ module.exports = function (Topics) {
|
|||||||
], callback);
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Topics.filterNewTids = function (tids, uid, callback) {
|
||||||
|
db.sortedSetScores('uid:' + uid + ':tids_read', tids, function (err, scores) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
tids = tids.filter(function (tid, index) {
|
||||||
|
return tid && !scores[index];
|
||||||
|
});
|
||||||
|
callback(null, tids);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user