diff --git a/public/src/admin.js b/public/src/admin.js index df5b4d3c7d..d504750add 100644 --- a/public/src/admin.js +++ b/public/src/admin.js @@ -18,7 +18,7 @@ var admin = {}; } } }); - }); + }); }; $(function() { diff --git a/public/src/forum/admin/categories.js b/public/src/forum/admin/categories.js index 78e173997a..6a6f2f9373 100644 --- a/public/src/forum/admin/categories.js +++ b/public/src/forum/admin/categories.js @@ -308,9 +308,11 @@ define(['uploader'], function(uploader) { uid: uid, privilege: privilege, set: !anchorEl.hasClass('active') - }, function(err, privileges) { - anchorEl.toggleClass('active', privileges[privilege]); - + }, function(err) { + if (err) { + return app.alertError(err.message); + } + anchorEl.toggleClass('active', !anchorEl.hasClass('active')); Categories.refreshPrivilegeList(cid); }); }); diff --git a/src/categories.js b/src/categories.js index 0b0e2dbe76..06b96c5c84 100644 --- a/src/categories.js +++ b/src/categories.js @@ -8,7 +8,6 @@ var db = require('./database'), Groups = require('./groups'), topics = require('./topics'), plugins = require('./plugins'), - CategoryTools = require('./categoryTools'), meta = require('./meta'), emitter = require('./emitter'), validator = require('validator'), @@ -60,6 +59,10 @@ var db = require('./database'), }); }; + Categories.exists = function(cid, callback) { + db.isSortedSetMember('categories:cid', cid, callback); + }; + Categories.getCategoryById = function(cid, start, end, uid, callback) { Categories.getCategoryData(cid, function(err, category) { if(err || !category) { diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js index 925e83e42e..8142a06c24 100644 --- a/src/categories/recentreplies.js +++ b/src/categories/recentreplies.js @@ -6,8 +6,7 @@ var async = require('async'), db = require('./../database'), posts = require('./../posts'), - topics = require('./../topics'), - CategoryTools = require('./../categoryTools'); + topics = require('./../topics'); module.exports = function(Categories) { Categories.getRecentReplies = function(cid, uid, count, callback) { diff --git a/src/categoryTools.js b/src/categoryTools.js deleted file mode 100644 index c965b9b17c..0000000000 --- a/src/categoryTools.js +++ /dev/null @@ -1,135 +0,0 @@ -"use strict"; - -var Groups = require('./groups'), - User = require('./user'), - categories = require('./categories'), - - async = require('async'), - db = require('./database'); - -var internals = { - isMember: function(key, candidate, next){ - Groups.exists(key, function(err, exists) { - if (exists) { - Groups.isMember(candidate, key, next); - } else { - next(null, null); - } - }); - }, - - isMemberOfGroupList: function(key, candidate, next){ - Groups.exists(key, function(err, exists) { - if (exists) { - Groups.isMemberOfGroupList(candidate, key, next); - } else { - next(null, null); - } - }); - } -}; - -var CategoryTools = {}; - -CategoryTools.exists = function(cid, callback) { - db.isSortedSetMember('categories:cid', cid, callback); -}; - -CategoryTools.privileges = function(cid, uid, callback) { - async.parallel({ - "disabled": function(next) { - categories.getCategoryField(cid, 'disabled', next); - }, - read: function(next) { - internals.isMember('cid:' + cid + ':privileges:read', uid, next); - }, - "topics:create": function(next) { - internals.isMember('cid:' + cid + ':privileges:topics:create', uid, next); - }, - "topics:reply": function(next) { - internals.isMember('cid:' + cid + ':privileges:topics:reply', uid, next); - }, - "groups:read": function(next) { - internals.isMemberOfGroupList('cid:' + cid + ':privileges:groups:read', uid, next); - }, - "groups:topics:create": function(next) { - internals.isMemberOfGroupList('cid:' + cid + ':privileges:groups:topics:create', uid, next); - }, - "groups:topics:reply": function(next) { - internals.isMemberOfGroupList('cid:' + cid + ':privileges:groups:topics:reply', uid, next); - }, - mods: function(next) { - User.isModerator(uid, cid, next); - }, - admin: function(next) { - User.isAdministrator(uid, next); - } - }, function(err, privileges) { - if (privileges) { - privileges.meta = { - read: ( - ( - parseInt(privileges.disabled, 10) !== 1 && - ( - (privileges['read'] === null && privileges['groups:read'] === null) || - privileges['read'] || privileges['groups:read'] - ) - ) || - privileges.mods || - privileges.admin - ), - "topics:create": ( - ( - parseInt(privileges.disabled, 10) !== 1 && - ( - (privileges['topics:create'] === null && privileges['groups:topics:create'] === null) || - privileges['topics:create'] || privileges['groups:topics:create'] - ) - ) || - privileges.mods || - privileges.admin - ), - "topics:reply": ( - ( - parseInt(privileges.disabled, 10) !== 1 && - ( - (privileges['topics:reply'] === null && privileges['groups:topics:reply'] === null) || - privileges['topics:reply'] || privileges['groups:topics:reply'] - ) - ) || - privileges.mods || - privileges.admin - ), - editable: privileges.mods || privileges.admin, - view_deleted: privileges.mods || privileges.admin - }; - } - - // console.log(privileges, cid, uid); - callback(err, privileges || null); - }); -}; - -CategoryTools.groupPrivileges = function(cid, groupName, callback) { - async.parallel({ - "groups:read":function(next) { - internals.isMember('cid:' + cid + ':privileges:groups:read', groupName, function(err, isMember){ - next(err, !!isMember); - }); - }, - "groups:topics:create":function(next) { - internals.isMember('cid:' + cid + ':privileges:groups:topics:create', groupName, function(err, isMember){ - next(err, !!isMember); - }); - }, - "groups:topics:reply":function(next) { - internals.isMember('cid:' + cid + ':privileges:groups:topics:reply', groupName, function(err, isMember){ - next(err, !!isMember); - }); - } - }, function(err, privileges) { - callback(err, privileges || null); - }); -}; - -module.exports = CategoryTools; diff --git a/src/controllers/categories.js b/src/controllers/categories.js index 58fd5e80d5..12d5f8346f 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -4,7 +4,7 @@ var categoriesController = {}, async = require('async'), qs = require('querystring'), nconf = require('nconf'), - categoryTools = require('./../categoryTools'), + privileges = require('../privileges'), user = require('./../user'), categories = require('./../categories'), topics = require('./../topics'); @@ -72,16 +72,16 @@ categoriesController.get = function(req, res, next) { }); }, function(next) { - categoryTools.privileges(cid, uid, function(err, categoryPrivileges) { + privileges.categories.get(cid, uid, function(err, categoryPrivileges) { if (err) { return next(err); } if (!categoryPrivileges.meta.read) { - next(new Error('[[error:no-privileges]]')); - } else { - next(null, categoryPrivileges); + return next(new Error('[[error:no-privileges]]')); } + + next(null, categoryPrivileges); }); }, function (privileges, next) { @@ -152,14 +152,14 @@ categoriesController.get = function(req, res, next) { } ], function (err, data) { if (err) { - if (err.message === 'not-enough-privileges') { - return res.redirect('403'); + if (err.message === '[[error:no-privileges]]') { + return res.locals.isAPI ? res.json(403, err.message) : res.redirect('403'); } else { - return res.redirect('404'); + return res.locals.isAPI ? res.json(404, 'not-found') : res.redirect('404'); } } - if(data.link) { + if (data.link) { return res.redirect(data.link); } diff --git a/src/controllers/index.js b/src/controllers/index.js index 31ea691136..9955eaaef8 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -17,7 +17,7 @@ var topicsController = require('./topics'), topics = require('./../topics'), plugins = require('./../plugins'), categories = require('./../categories'), - categoryTools = require('./../categoryTools'); + privileges = require('../privileges'); @@ -69,12 +69,6 @@ Controllers.home = function(req, res, next) { return !category.disabled; }); - function canSee(category, next) { - categoryTools.privileges(category.cid, ((req.user) ? req.user.uid || 0 : 0), function(err, privileges) { - next(!err && privileges.meta.read); - }); - } - function getRecentReplies(category, callback) { categories.getRecentReplies(category.cid, uid, parseInt(category.numRecentReplies, 10), function (err, posts) { category.posts = posts; @@ -83,7 +77,11 @@ Controllers.home = function(req, res, next) { }); } - async.filter(data.categories, canSee, function(visibleCategories) { + async.filter(data.categories, function (category, next) { + privileges.categories.canRead(category.cid, uid, function(err, canRead) { + next(!err && canRead); + }); + }, function(visibleCategories) { data.categories = visibleCategories; async.each(data.categories, getRecentReplies, function (err) { diff --git a/src/controllers/topics.js b/src/controllers/topics.js index ed70e7fe38..d407c07168 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -147,7 +147,7 @@ topicsController.get = function(req, res, next) { } ], function (err, data) { if (err) { - if (err.message === 'not-enough-privileges') { + if (err.message === '[[error:no-privileges]]') { return res.locals.isAPI ? res.json(403, err.message) : res.redirect('403'); } else { return res.locals.isAPI ? res.json(404, 'not-found') : res.redirect('404'); diff --git a/src/privileges/categories.js b/src/privileges/categories.js index aa1b7d233f..af2f50cdaf 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -4,6 +4,7 @@ var async = require('async'), user = require('../user'), + groups = require('../groups'), helpers = require('./helpers'); @@ -11,6 +12,38 @@ module.exports = function(privileges) { privileges.categories = {}; + privileges.categories.get = function(cid, uid, callback) { + async.parallel({ + 'topics:create': function(next) { + helpers.allowedTo('topics:create', uid, cid, next); + }, + read: function(next) { + helpers.allowedTo('read', uid, cid, next); + }, + isAdministrator: function(next) { + user.isAdministrator(uid, next); + }, + isModerator: function(next) { + user.isModerator(uid, cid, next); + } + }, function(err, results) { + if(err) { + return callback(err); + } + + var editable = results.isAdministrator || results.isModerator; + + callback(null, { + meta: { + 'topics:create': results['topics:create'], + editable: editable, + view_deleted: editable, + read: results.read + } + }); + }); + }; + privileges.categories.canRead = function(cid, uid, callback) { helpers.some([ function(next) { @@ -25,4 +58,61 @@ module.exports = function(privileges) { ], callback); }; + privileges.categories.canMoveAllTopics = function(currentCid, targetCid, uid, callback) { + async.parallel({ + isAdministrator: function(next) { + user.isAdministrator(uid, next); + }, + moderatorOfCurrent: function(next) { + user.isModerator(uid, currentCid, next); + }, + moderatorOfTarget: function(next) { + user.isModerator(uid, targetCid, next); + } + }, function(err, results) { + if (err) { + return callback(err); + } + + callback(null, results.isAdministrator || (results.moderatorOfCurrent && results.moderatorOfTarget)); + }); + }; + + privileges.categories.userPrivileges = function(cid, uid, callback) { + async.parallel({ + read: function(next) { + helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:read', uid, next); + }, + 'topics:create': function(next) { + helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:topics:create', uid, next); + }, + 'topics:reply': function(next) { + helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:topics:reply', uid, next); + }, + mods: function(next) { + user.isModerator(uid, cid, next); + } + }, callback); + }; + + privileges.categories.groupPrivileges = function(cid, groupName, callback) { + async.parallel({ + 'groups:read': function(next) { + helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:groups:read', groupName, function(err, isMember){ + next(err, !!isMember); + }); + }, + 'groups:topics:create': function(next) { + helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:groups:topics:create', groupName, function(err, isMember){ + next(err, !!isMember); + }); + }, + 'groups:topics:reply': function(next) { + helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:groups:topics:reply', groupName, function(err, isMember){ + next(err, !!isMember); + }); + } + }, callback); + }; + }; diff --git a/src/privileges/helpers.js b/src/privileges/helpers.js index dcaa0c9b76..2bf2f49226 100644 --- a/src/privileges/helpers.js +++ b/src/privileges/helpers.js @@ -32,10 +32,10 @@ helpers.allowedTo = function(privilege, uid, cid, callback) { async.parallel({ hasUserPrivilege: function(next) { - isMember(groups.isMember, 'cid:' + cid + ':privileges:' + privilege, uid, next); + helpers.isMember(groups.isMember, 'cid:' + cid + ':privileges:' + privilege, uid, next); }, hasGroupPrivilege: function(next) { - isMember(groups.isMemberOfGroupList, 'cid:' + cid + ':privileges:groups:' + privilege, uid, next); + helpers.isMember(groups.isMemberOfGroupList, 'cid:' + cid + ':privileges:groups:' + privilege, uid, next); }, }, function(err, results) { if (err) { @@ -47,7 +47,7 @@ helpers.allowedTo = function(privilege, uid, cid, callback) { }); }; -function isMember(method, group, uid, callback) { +helpers.isMember = function(method, group, uid, callback) { groups.exists(group, function(err, exists) { if (err) { return callback(err); diff --git a/src/privileges/topics.js b/src/privileges/topics.js index 55286726e4..7c82452f93 100644 --- a/src/privileges/topics.js +++ b/src/privileges/topics.js @@ -65,6 +65,20 @@ module.exports = function(privileges) { }); }; + privileges.topics.canCreate = function(cid, uid, callback) { + helpers.some([ + function(next) { + helpers.allowedTo('topics:create', uid, cid, next); + }, + function(next) { + user.isModerator(uid, cid, next); + }, + function(next) { + user.isAdministrator(uid, next); + } + ], callback); + }; + privileges.topics.canReply = function(tid, uid, callback) { topics.getTopicField(tid, 'cid', function(err, cid) { if (err) { diff --git a/src/routes/debug.js b/src/routes/debug.js index 6d6641615f..2534576d20 100644 --- a/src/routes/debug.js +++ b/src/routes/debug.js @@ -54,11 +54,10 @@ module.exports = function(app, middleware, controllers) { }); app.get('/test', function(req, res) { - var tools = require('../categoryTools'); - tools.privileges(1, 2, function() { - console.log(arguments); - }) - res.send(200); + var privileges = require('../privileges'); + privileges.topics.get(1299, 1, function(err, result) { + res.json(result); + }); }); }); }; diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index 9a03319baa..aa653d516f 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -7,7 +7,6 @@ var groups = require('../groups'), user = require('../user'), topics = require('../topics'), categories = require('../categories'), - CategoryTools = require('../categoryTools'), logger = require('../logger'), events = require('../events'), db = require('../database'), diff --git a/src/socket.io/admin/categories.js b/src/socket.io/admin/categories.js index dba2efca97..4c70599e14 100644 --- a/src/socket.io/admin/categories.js +++ b/src/socket.io/admin/categories.js @@ -3,7 +3,7 @@ var groups = require('../../groups'), user = require('../../user'), categories = require('../../categories'), - categoryTools = require('../../categoryTools'), + privileges = require('../../privileges'), async = require('async'), Categories = {}; @@ -32,8 +32,12 @@ Categories.search = function(socket, data, callback) { cid = data.cid; user.search(username, function(err, data) { + if (err) { + return callback(err); + } + async.map(data.users, function(userObj, next) { - categoryTools.privileges(cid, userObj.uid, function(err, privileges) { + privileges.categories.userPrivileges(cid, userObj.uid, function(err, privileges) { if(err) { return next(err); } @@ -50,22 +54,7 @@ Categories.setPrivilege = function(socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } - var cid = data.cid, - uid = data.uid, - privilege = data.privilege, - set = data.set, - cb = function(err) { - if(err) { - return callback(err); - } - categoryTools.privileges(cid, uid, callback); - }; - - if (set) { - groups.join('cid:' + cid + ':privileges:' + privilege, uid, cb); - } else { - groups.leave('cid:' + cid + ':privileges:' + privilege, uid, cb); - } + groups[data.set ? 'join' : 'leave']('cid:' + data.cid + ':privileges:' + data.privilege, data.uid, callback); }; Categories.getPrivilegeSettings = function(socket, cid, callback) { @@ -119,7 +108,7 @@ Categories.groupsList = function(socket, cid, callback) { } async.map(data, function(groupObj, next) { - categoryTools.groupPrivileges(cid, groupObj.name, function(err, privileges) { + privileges.categories.groupPrivileges(cid, groupObj.name, function(err, privileges) { if(err) { return next(err); } diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index a3ca8abb37..117640793d 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -2,19 +2,19 @@ var async = require('async'), categories = require('../categories'), - categoryTools = require('../categoryTools'), + privileges = require('../privileges'), meta = require('./../meta'), user = require('./../user'), SocketCategories = {}; SocketCategories.getRecentReplies = function(socket, cid, callback) { - categoryTools.privileges(cid, socket.uid, function(err, privileges) { + privileges.categories.canRead(cid, socket.uid, function(err, canRead) { if (err) { return callback(err); } - if (!privileges || !privileges.meta.read) { + if (!canRead) { return callback(null, []); } @@ -33,7 +33,7 @@ SocketCategories.loadMore = function(socket, data, callback) { async.parallel({ privileges: function(next) { - categoryTools.privileges(data.cid, socket.uid, next); + privileges.categories.get(data.cid, socket.uid, next); }, settings: function(next) { user.getSettings(socket.uid, next); diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index 2da898dc35..d0cf8e716e 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -5,7 +5,6 @@ var topics = require('../topics'), categories = require('../categories'), privileges = require('../privileges'), threadTools = require('../threadTools'), - categoryTools = require('../categoryTools'), websockets = require('./index'), user = require('../user'), db = require('./../database'), @@ -275,20 +274,9 @@ SocketTopics.moveAll = function(socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } - async.parallel({ - from: function(next) { - categoryTools.privileges(data.currentCid, socket.uid, next); - }, - to: function(next) { - categoryTools.privileges(data.cid, socket.uid, next); - } - }, function(err, results) { - if (err) { - return callback(err); - } - - if (!results.from.admin && (!results.from.mods || !results.to.mods)) { - return callback(new Error('[[error:no-privileges]]')); + privileges.categories.canMoveAllTopics(data.currentCid, data.cid, data.uid, function(err, canMove) { + if (err || canMove) { + return callback(err || new Error('[[error:no-privileges]]')); } categories.getTopicIds(data.currentCid, 0, -1, function(err, tids) { diff --git a/src/threadTools.js b/src/threadTools.js index 8b13cb6dfd..c476e461f5 100644 --- a/src/threadTools.js +++ b/src/threadTools.js @@ -7,7 +7,6 @@ var winston = require('winston'), db = require('./database'), topics = require('./topics'), categories = require('./categories'), - CategoryTools = require('./categoryTools'), user = require('./user'), notifications = require('./notifications'), posts = require('./posts'), diff --git a/src/topics.js b/src/topics.js index 478d76066c..0763a13a0c 100644 --- a/src/topics.js +++ b/src/topics.js @@ -10,8 +10,6 @@ var async = require('async'), plugins = require('./plugins'), user = require('./user'), categories = require('./categories'), - categoryTools = require('./categoryTools'), - threadTools = require('./threadTools'), privileges = require('./privileges'); (function(Topics) { @@ -23,7 +21,6 @@ var async = require('async'), require('./topics/posts')(Topics); require('./topics/follow')(Topics); - Topics.getTopicData = function(tid, callback) { Topics.getTopicsData([tid], function(err, topics) { if (err) { @@ -200,7 +197,7 @@ var async = require('async'), if (privilegeCache[topicData.cid]) { return next(null, privilegeCache[topicData.cid]); } - categoryTools.privileges(topicData.cid, uid, next); + privileges.categories.get(topicData.cid, uid, next); }, categoryData: function(next) { if (categoryCache[topicData.cid]) { diff --git a/src/topics/create.js b/src/topics/create.js index 9c95c65c66..e47216de08 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -2,15 +2,15 @@ 'use strict'; var async = require('async'), - db = require('./../database'), - utils = require('./../../public/src/utils'), - plugins = require('./../plugins'), - user = require('./../user'), - meta = require('./../meta'), - posts = require('./../posts'), - threadTools = require('./../threadTools'), + db = require('../database'), + utils = require('../../public/src/utils'), + plugins = require('../plugins'), + user = require('../user'), + meta = require('../meta'), + posts = require('../posts'), + threadTools = require('../threadTools'), privileges = require('../privileges'), - categoryTools = require('./../categoryTools'); + categories = require('../categories'); module.exports = function(Topics) { @@ -93,16 +93,16 @@ module.exports = function(Topics) { }); }, function(next) { - categoryTools.exists(cid, next); + categories.exists(cid, next); }, function(categoryExists, next) { if (!categoryExists) { return next(new Error('[[error:no-category]]')); } - categoryTools.privileges(cid, uid, next); + privileges.topics.canCreate(cid, uid, next); }, - function(privileges, next) { - if(!privileges.meta['topics:create']) { + function(canCreate, next) { + if(!canCreate) { return next(new Error('[[error:no-privileges]]')); } next();