From 423405782164e9da5042399ba77371333ecf96cc Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 14 May 2014 17:53:23 -0400 Subject: [PATCH] first pass for #1518 this only handles postTools privileges, topic and category will follow --- src/postTools.js | 53 +++--------------- src/posts.js | 19 +++++-- src/privileges.js | 8 +++ src/privileges/helpers.js | 66 ++++++++++++++++++++++ src/privileges/posts.js | 112 ++++++++++++++++++++++++++++++++++++++ src/socket.io/posts.js | 10 ++-- src/topics/fork.js | 11 ++-- src/topics/posts.js | 8 +-- 8 files changed, 220 insertions(+), 67 deletions(-) create mode 100644 src/privileges.js create mode 100644 src/privileges/helpers.js create mode 100644 src/privileges/posts.js diff --git a/src/postTools.js b/src/postTools.js index 91a9154261..47a2daa15b 100644 --- a/src/postTools.js +++ b/src/postTools.js @@ -9,6 +9,7 @@ var winston = require('winston'), posts = require('./posts'), topics = require('./topics'), threadTools = require('./threadTools'), + privileges = require('./privileges'), user = require('./user'), utils = require('../public/src/utils'), plugins = require('./plugins'), @@ -31,47 +32,6 @@ var winston = require('winston'), }); }; - PostTools.privileges = function(pid, uid, callback) { - async.parallel({ - topicPrivs: function(next) { - posts.getPostField(pid, 'tid', function(err, tid) { - threadTools.privileges(tid, uid, next); - }); - }, - isOwner: function(next) { - posts.getPostField(pid, 'uid', function(err, author) { - next(null, parseInt(author, 10) === parseInt(uid, 10)); - }); - }, - hasEnoughRep: function(next) { - if (parseInt(meta.config['privileges:disabled'], 10)) { - return next(null, false); - } else { - user.getUserField(uid, 'reputation', function(err, reputation) { - if (err) { - return next(null, false); - } - next(null, parseInt(reputation, 10) >= parseInt(meta.config['privileges:manage_content'], 10)); - }); - } - } - }, function(err, results) { - if(err) { - return callback(err); - } - - callback(null, { - meta: { - read: results.topicPrivs.meta.read, - editable: results.topicPrivs.meta.editable || results.isOwner || results.hasEnoughRep, - view_deleted: results.topicPrivs.meta.view_deleted || results.isOwner || results.hasEnoughRep, - move: results.topicPrivs.admin || results.topicPrivs.mods - } - }); - }); - }; - - PostTools.edit = function(uid, pid, title, content, options, callback) { options = options || {}; @@ -120,8 +80,8 @@ var winston = require('winston'), }, callback); } - PostTools.privileges(pid, uid, function(err, privileges) { - if (err || !privileges.meta.editable) { + privileges.posts.canEdit(pid, uid, function(err, canEdit) { + if (err || !canEdit) { return callback(err || new Error('[[error:no-privileges]]')); } @@ -161,10 +121,11 @@ var winston = require('winston'), } else if(parseInt(deleted, 10) !== 1 && !isDelete) { return next(new Error('[[error:post-already-restored]]')); } - PostTools.privileges(pid, uid, next); + + privileges.posts.canEdit(pid, uid, next); }, - function(privileges, next) { - if (!privileges || !privileges.meta.editable) { + function(canEdit, next) { + if (!canEdit) { return next(new Error('[[error:no-privileges]]')); } next(); diff --git a/src/posts.js b/src/posts.js index 041434c67c..6581882f97 100644 --- a/src/posts.js +++ b/src/posts.js @@ -6,6 +6,7 @@ var db = require('./database'), topics = require('./topics'), favourites = require('./favourites'), postTools = require('./postTools'), + privileges = require('./privileges'), categories = require('./categories'), plugins = require('./plugins'), meta = require('./meta'), @@ -163,8 +164,8 @@ var db = require('./database'), } async.filter(pids, function(pid, next) { - postTools.privileges(pid, callerUid, function(err, privileges) { - next(!err && privileges.meta.read); + privileges.posts.canRead(pid, callerUid, function(err, canRead) { + next(!err && canRead); }); }, function(pids) { if (!(pids && pids.length)) { @@ -215,8 +216,8 @@ var db = require('./database'), } async.filter(pids, function(pid, next) { - postTools.privileges(pid, uid, function(err, privileges) { - next(!err && privileges.meta.read); + privileges.posts.canRead(pid, uid, function(err, canRead) { + next(!err && canRead); }); }, function(pids) { Posts.getPostSummaryByPids(pids, true, callback); @@ -481,4 +482,14 @@ var db = require('./database'), }); }; + Posts.isOwner = function(pid, uid, callback) { + Posts.getPostField(pid, 'uid', function(err, author) { + if (err) { + return callback(err); + } + callback(null, parseInt(author, 10) === parseInt(uid, 10)); + }); + }; + + }(exports)); diff --git a/src/privileges.js b/src/privileges.js new file mode 100644 index 0000000000..275db8b724 --- /dev/null +++ b/src/privileges.js @@ -0,0 +1,8 @@ + + +var privileges = {}; + +require('./privileges/posts')(privileges); + + +module.exports = privileges; \ No newline at end of file diff --git a/src/privileges/helpers.js b/src/privileges/helpers.js new file mode 100644 index 0000000000..f57fcc73fd --- /dev/null +++ b/src/privileges/helpers.js @@ -0,0 +1,66 @@ + +'use strict'; + +var async = require('async'), + + meta = require('../meta'), + user = require('../user'), + groups = require('../groups'), + categories = require('../categories'); + +var helpers = {}; + +helpers.allowedTo = function(privilege, uid, cid, callback) { + categories.getCategoryField(cid, 'disabled', function(err, disabled) { + if (err) { + return callback(err); + } + + if (parseInt(disabled, 10) === 1) { + return callback(null, false); + } + + async.parallel({ + hasUserPrivilege: function(next) { + hasPrivilege(groups.isMember, 'cid:' + cid + ':privileges:' + privilege, uid, next); + }, + hasGroupPrivilege: function(next) { + hasPrivilege(groups.isMemberOfGroupList, 'cid:' + cid + ':privileges:groups:' + privilege, uid, next); + }, + }, function(err, results) { + if (err) { + return callback(err); + } + callback(null, results.hasUserPrivilege && results.hasGroupPrivilege); + }); + }); +}; + +function hasPrivilege(method, group, uid, callback) { + groups.exists(group, function(err, exists) { + if (err) { + return callback(err); + } + + if (!exists) { + return callback(null, true); + } + + method(group, uid, callback); + }); +} + +helpers.hasEnoughReputationFor = function(privilege, uid, callback) { + if (parseInt(meta.config['privileges:disabled'], 10)) { + return callback(null, false); + } + + user.getUserField(uid, 'reputation', function(err, reputation) { + if (err) { + return callback(null, false); + } + callback(null, parseInt(reputation, 10) >= parseInt(meta.config[privilege], 10)); + }); +}; + +module.exports = helpers; \ No newline at end of file diff --git a/src/privileges/posts.js b/src/privileges/posts.js new file mode 100644 index 0000000000..8894dd1509 --- /dev/null +++ b/src/privileges/posts.js @@ -0,0 +1,112 @@ + +'use strict'; + +var async = require('async'), + + posts = require('../posts'), + user = require('../user'), + helpers = require('./helpers'), + groups = require('../groups'), + categories = require('../categories'); + +module.exports = function(privileges) { + + privileges.posts = {}; + + privileges.posts.get = function(pid, uid, callback) { + + async.parallel({ + isOwner: function(next) { + posts.isOwner(pid, uid, next); + }, + manage_content: function(next) { + helpers.hasEnoughReputationFor('privileges:manage_content', uid, next); + }, + manage_topic: function(next) { + helpers.hasEnoughReputationFor('privileges:manage_topic', uid, next); + }, + isAdministrator: function(next) { + user.isAdministrator(uid, next); + }, + isModerator: function(next) { + posts.getCidByPid(pid, function(err, cid) { + if (err) { + return next(err); + } + user.isModerator(uid, cid, next); + }); + } + }, function(err, results) { + if(err) { + return callback(err); + } + + var editable = results.isAdministrator || results.isModerator || results.manage_content || results.manage_topic || results.isOwner; + + callback(null, { + meta: { + editable: editable, + view_deleted: editable, + move: results.isAdministrator || results.isModerator + } + }); + }); + }; + + privileges.posts.canRead = function(pid, uid, callback) { + posts.getCidByPid(pid, function(err, cid) { + if (err) { + return callback(err); + } + + async.some([ + function(next) { + helpers.allowedTo('read', uid, cid, next); + }, + function(next) { + user.isModerator(uid, cid, next); + }, + function(next) { + user.isAdministrator(uid, next); + } + ], function(task, next) { + task(function(err, result) { + next(!err && result); + }); + }, function(result) { + callback(null, result); + }); + }); + }; + + privileges.posts.canEdit = function(pid, uid, callback) { + async.some([ + function(next) { + posts.isOwner(pid, uid, next); + }, + function(next) { + helpers.hasEnoughReputationFor('privileges:manage_content', uid, next); + }, + function(next) { + helpers.hasEnoughReputationFor('privileges:manage_topic', uid, next); + }, + function(next) { + posts.getCidByPid(pid, function(err, cid) { + if (err) { + return next(err); + } + user.isModerator(uid, cid, next); + }); + }, + function(next) { + user.isAdministrator(uid, next); + } + ], function(task, next) { + task(function(err, result) { + next(!err && result); + }); + }, function(result) { + callback(null, result); + }); + }; +}; diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 15d8a6b216..278a1ab2d3 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -5,6 +5,7 @@ var async = require('async'), db = require('../database'), posts = require('../posts'), + privileges = require('../privileges'), meta = require('../meta'), topics = require('../topics'), favourites = require('../favourites'), @@ -17,7 +18,6 @@ var async = require('async'), SocketPosts = {}; - SocketPosts.reply = function(socket, data, callback) { if (!socket.uid && !parseInt(meta.config.allowGuestPosting, 10)) { @@ -127,10 +127,10 @@ function sendNotificationToPostOwner(data, uid, notification) { SocketPosts.getRawPost = function(socket, pid, callback) { async.waterfall([ function(next) { - postTools.privileges(pid, socket.uid, next); + privileges.posts.canRead(pid, socket.uid, next); }, - function(privileges, next) { - if (!privileges || !privileges.meta.read) { + function(canRead, next) { + if (!canRead) { return next(new Error('[[error:no-privileges]]')); } posts.getPostFields(pid, ['content', 'deleted'], next); @@ -205,7 +205,7 @@ function deleteOrRestore(command, socket, data, callback) { } SocketPosts.getPrivileges = function(socket, pid, callback) { - postTools.privileges(pid, socket.uid, function(err, privileges) { + privileges.posts.get(pid, socket.uid, function(err, privileges) { if(err) { return callback(err); } diff --git a/src/topics/fork.js b/src/topics/fork.js index 27b5903666..35880cc2ea 100644 --- a/src/topics/fork.js +++ b/src/topics/fork.js @@ -7,6 +7,7 @@ var async = require('async'), db = require('./../database'), posts = require('./../posts'), + privileges = require('../privileges'), postTools = require('./../postTools'), threadTools = require('./../threadTools'); @@ -52,16 +53,12 @@ module.exports = function(Topics) { }); function move(pid, next) { - postTools.privileges(pid, uid, function(err, privileges) { - if(err) { + privileges.posts.canEdit(pid, uid, function(err, canEdit) { + if(err || !canEdit) { return next(err); } - if(privileges.meta.editable) { - Topics.movePostToTopic(pid, tid, next); - } else { - next(); - } + Topics.movePostToTopic(pid, tid, next); }); } }); diff --git a/src/topics/posts.js b/src/topics/posts.js index ac2c57843f..b531631b6a 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -8,9 +8,7 @@ var async = require('async'), emitter = require('./../emitter'), favourites = require('./../favourites'), posts = require('./../posts'), - postTools = require('./../postTools'); - - + privileges = require('../privileges'); module.exports = function(Topics) { @@ -52,7 +50,7 @@ module.exports = function(Topics) { }, privileges : function(next) { async.map(pids, function (pid, next) { - postTools.privileges(pid, uid, next); + privileges.posts.get(pid, uid, next); }, next); } }, function(err, results) { @@ -66,7 +64,7 @@ module.exports = function(Topics) { postData[i].upvoted = results.voteData[i].upvoted; postData[i].downvoted = results.voteData[i].downvoted; postData[i].votes = postData[i].votes || 0; - postData[i].display_moderator_tools = parseInt(uid, 10) !== 0 && results.privileges[i].meta.editable; + postData[i].display_moderator_tools = results.privileges[i].meta.editable; postData[i].display_move_tools = results.privileges[i].meta.move; postData[i].selfPost = parseInt(uid, 10) === parseInt(postData[i].uid, 10);