From fed8cc6d53388ae1a0acdfe666f3328545ae4fdf Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 29 Jul 2014 21:51:46 -0400 Subject: [PATCH] optimize privileges and assorted fixes. * new methods privileges.categories.filter privileges.topics.filter privileges.posts.filter they take a list of ids and a privilege, and return the filtered list of ids, faster than doing async.filter and calling the db for each id. * remove event listeners on recent page before adding * group.exists works for both single group names and arrays * helpers.allowedTo works for both a single cid and an array of cids * moved filter:topic.post hook right before topic creation. * moved filter:topic.reply hook right before topic reply. --- public/src/forum/recent.js | 2 +- src/categories.js | 44 ++++++++------- src/groups.js | 6 +- src/posts.js | 22 ++++---- src/privileges/categories.js | 74 ++++++++++++++++++------- src/privileges/helpers.js | 104 +++++++++++++++++++++-------------- src/privileges/posts.js | 25 +++++++++ src/privileges/topics.js | 30 ++++++++++ src/search.js | 10 ++-- src/topics.js | 15 +++-- src/topics/create.js | 25 ++++----- src/topics/unread.js | 11 ++-- src/user/notifications.js | 2 - 13 files changed, 242 insertions(+), 128 deletions(-) diff --git a/public/src/forum/recent.js b/public/src/forum/recent.js index 3f0885690d..b4a27e664b 100644 --- a/public/src/forum/recent.js +++ b/public/src/forum/recent.js @@ -56,7 +56,7 @@ define('forum/recent', ['forum/infinitescroll'], function(infinitescroll) { Recent.watchForNewPosts = function () { newPostCount = 0; newTopicCount = 0; - + Recent.removeListeners(); socket.on('event:new_topic', onNewTopic); socket.on('event:new_post', onNewPost); }; diff --git a/src/categories.js b/src/categories.js index 80ed12e621..ceae7d8f01 100644 --- a/src/categories.js +++ b/src/categories.js @@ -198,19 +198,21 @@ var db = require('./database'), return callback(null, []); } - Categories.getCategories(cids, uid, function(err, categories) { + privileges.categories.filter('find', cids, uid, function(err, cids) { if (err) { return callback(err); } - async.filter(categories, function (category, next) { - if (category.disabled) { - return next(false); + + Categories.getCategories(cids, uid, function(err, categories) { + if (err) { + return callback(err); } - privileges.categories.can('find', category.cid, uid, function(err, findable) { - next(!err && findable); + + categories = categories.filter(function(category) { + return !category.disabled; }); - }, function(visibleCategories) { - callback(null, visibleCategories); + + callback(null, categories); }); }); }); @@ -218,18 +220,15 @@ var db = require('./database'), Categories.getModerators = function(cid, callback) { Groups.get('cid:' + cid + ':privileges:mods', {}, function(err, groupObj) { - if (!err) { - if (groupObj.members && groupObj.members.length) { - user.getMultipleUserFields(groupObj.members, ['uid', 'username', 'userslug', 'picture'], function(err, moderators) { - callback(err, moderators); - }); - } else { - callback(null, []); - } - } else { - // Probably no mods - callback(null, []); + if (err) { + return callback(err); } + + if (!Array.isArray(groupObj) || !groupObj.members.length) { + return callback(null, []); + } + + user.getMultipleUserFields(groupObj.members, ['uid', 'username', 'userslug', 'picture'], callback); }); }; @@ -309,11 +308,14 @@ var db = require('./database'), }; Categories.getCategories = function(cids, uid, callback) { - - if (!Array.isArray(cids) || cids.length === 0) { + if (!Array.isArray(cids)) { return callback(new Error('[[error:invalid-cid]]')); } + if (!cids.length) { + return callback(null, []); + } + async.parallel({ categories: function(next) { Categories.getCategoriesData(cids, next); diff --git a/src/groups.js b/src/groups.js index 294e8c134f..8164ae457c 100644 --- a/src/groups.js +++ b/src/groups.js @@ -183,7 +183,11 @@ }; Groups.exists = function(name, callback) { - db.isSetMember('groups', name, callback); + if (Array.isArray(name)) { + db.isSetMembers('groups', name, callback); + } else { + db.isSetMember('groups', name, callback); + } }; Groups.create = function(name, description, callback) { diff --git a/src/posts.js b/src/posts.js index c272dfb78b..df218c14c8 100644 --- a/src/posts.js +++ b/src/posts.js @@ -178,11 +178,14 @@ var async = require('async'), return callback(err); } - async.filter(pids, function(pid, next) { - privileges.posts.can('read', pid, uid, function(err, canRead) { - next(!err && canRead); - }); - }, function(pids) { + if (!Array.isArray(pids) || !pids.length) { + return callback(null, []); + } + + privileges.posts.filter('read', pids, uid, function(err, pids) { + if (err) { + return callback(err); + } Posts.getPostSummaryByPids(pids, {stripTags: true}, callback); }); }); @@ -487,11 +490,10 @@ var async = require('async'), return callback(err); } - async.filter(pids, function(pid, next) { - privileges.posts.can('read', pid, callerUid, function(err, canRead) { - next(!err && canRead); - }); - }, function(pids) { + privileges.posts.filter('read', pids, callerUid, function(err, pids) { + if (err) { + return callback(err); + } getPostsFromSet('uid:' + uid + ':posts', pids, callback); }); }); diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 7509808f60..11b4767b30 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -4,6 +4,7 @@ var async = require('async'), user = require('../user'), + categories = require('../categories'), groups = require('../groups'), helpers = require('./helpers'); @@ -43,17 +44,54 @@ module.exports = function(privileges) { }; privileges.categories.can = function(privilege, cid, uid, callback) { - helpers.some([ - function(next) { - helpers.allowedTo(privilege, uid, cid, next); + categories.getCategoryField(cid, 'disabled', function(err, disabled) { + if (err) { + return callback(err); + } + + if (parseInt(disabled, 10) === 1) { + return callback(null, false); + } + + helpers.some([ + function(next) { + helpers.allowedTo(privilege, uid, cid, next); + }, + function(next) { + user.isModerator(uid, cid, next); + }, + function(next) { + user.isAdministrator(uid, next); + } + ], callback); + }); + }; + + privileges.categories.filter = function(privilege, cids, uid, callback) { + async.parallel({ + allowedTo: function(next) { + helpers.allowedTo(privilege, uid, cids, next); }, - function(next) { - user.isModerator(uid, cid, next); + isModerators: function(next) { + user.isModerator(uid, cids, next); }, - function(next) { + isAdmin: function(next) { user.isAdministrator(uid, next); } - ], callback); + }, function(err, results) { + if (err) { + return callback(err); + } + + if (results.isAdmin) { + return callback(null, cids); + } + + cids = cids.filter(function(cid, index) { + return results.allowedTo[index] || results.isModerators[index]; + }); + callback(null, cids); + }); }; privileges.categories.canMoveAllTopics = function(currentCid, targetCid, uid, callback) { @@ -78,15 +116,15 @@ module.exports = function(privileges) { privileges.categories.userPrivileges = function(cid, uid, callback) { async.parallel({ - find: async.apply(helpers.isMember, groups.isMember, 'cid:' + cid + ':privileges:find', uid), + find: async.apply(groups.isMember, uid, 'cid:' + cid + ':privileges:find'), read: function(next) { - helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:read', uid, next); + groups.isMember(uid, 'cid:' + cid + ':privileges:read', next); }, 'topics:create': function(next) { - helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:topics:create', uid, next); + groups.isMember(uid, 'cid:' + cid + ':privileges:topics:create', next); }, 'topics:reply': function(next) { - helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:topics:reply', uid, next); + groups.isMember(uid, 'cid:' + cid + ':privileges:topics:reply', next); }, mods: function(next) { user.isModerator(uid, cid, next); @@ -96,21 +134,15 @@ module.exports = function(privileges) { privileges.categories.groupPrivileges = function(cid, groupName, callback) { async.parallel({ - 'groups:find': async.apply(helpers.isMember, groups.isMember, 'cid:' + cid + ':privileges:groups:find', groupName), + 'groups:find': async.apply(groups.isMember, groupName, 'cid:' + cid + ':privileges:groups:find'), 'groups:read': function(next) { - helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:groups:read', groupName, function(err, isMember){ - next(err, !!isMember); - }); + groups.isMember(groupName, 'cid:' + cid + ':privileges:groups:read', next); }, 'groups:topics:create': function(next) { - helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:groups:topics:create', groupName, function(err, isMember){ - next(err, !!isMember); - }); + groups.isMember(groupName, 'cid:' + cid + ':privileges:groups:topics:create', next); }, 'groups:topics:reply': function(next) { - helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:groups:topics:reply', groupName, function(err, isMember){ - next(err, !!isMember); - }); + groups.isMember(groupName, 'cid:' + cid + ':privileges:groups:topics:reply', next); } }, callback); }; diff --git a/src/privileges/helpers.js b/src/privileges/helpers.js index 642cf36b26..778f3a84df 100644 --- a/src/privileges/helpers.js +++ b/src/privileges/helpers.js @@ -2,7 +2,7 @@ 'use strict'; var async = require('async'), - + db = require('../database'), meta = require('../meta'), user = require('../user'), groups = require('../groups'), @@ -20,67 +20,87 @@ helpers.some = function(tasks, callback) { }); }; -helpers.allowedTo = function(privilege, uid, cid, callback) { - categories.getCategoryField(cid, 'disabled', function(err, disabled) { +helpers.allowedTo = function(privilege, uid, cids, callback) { + + if (!Array.isArray(cids)) { + cids = [cids]; + } + + if (parseInt(uid, 10) === 0) { + return isGuestAllowedTo(privilege, cids, callback); + } + + var userKeys = [], groupKeys = []; + for (var i=0; i