From 3e86bdb38f2c7b35fa0ce23f0e160e5952f4d438 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 15 May 2014 10:38:02 -0400 Subject: [PATCH] more work on #1518 still needs more work, category is next --- public/src/forum/topic.js | 9 +- public/src/forum/topic/threadTools.js | 71 +++++++-------- src/controllers/topics.js | 14 +-- src/privileges.js | 3 +- src/privileges/categories.js | 28 ++++++ src/privileges/helpers.js | 12 ++- src/privileges/posts.js | 44 ++++------ src/privileges/topics.js | 122 ++++++++++++++++++++++++++ src/routes/feeds.js | 17 ++-- src/socket.io/posts.js | 9 +- src/socket.io/topics.js | 27 +++--- src/threadTools.js | 32 ------- src/topics.js | 11 +-- src/topics/create.js | 12 +-- src/topics/unread.js | 6 +- 15 files changed, 269 insertions(+), 148 deletions(-) create mode 100644 src/privileges/categories.js create mode 100644 src/privileges/topics.js diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 460bfa43b6..3d4775b774 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -278,7 +278,7 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', pagination.recreatePaginationLinks(newPageCount); - if(pagination.currentPage === pagination.pageCount) { + if (pagination.currentPage === pagination.pageCount) { createNewPosts(data); } else if(data.posts && data.posts.length && parseInt(data.posts[0].uid, 10) === parseInt(app.uid, 10)) { pagination.loadPage(pagination.pageCount); @@ -390,8 +390,11 @@ define(['forum/pagination', 'forum/topic/threadTools', 'forum/topic/postTools', } function toggleModTools(postHtml, privileges) { - postHtml.find('.edit, .delete').toggleClass('none', !privileges.editable); - postHtml.find('.move').toggleClass('none', !privileges.move); + postHtml.find('.edit, .delete').toggleClass('none', !privileges.meta.editable); + postHtml.find('.move').toggleClass('none', !privileges.meta.move); + postHtml.find('.reply, .quote').toggleClass('none', !$('.post_reply').length) + var isSelfPost = parseInt(postHtml.attr('data-uid'), 10) === parseInt(app.uid, 10); + postHtml.find('.chat, .flag').toggleClass('none', isSelfPost); } function loadMorePosts(tid, after, callback) { diff --git a/public/src/forum/topic/threadTools.js b/public/src/forum/topic/threadTools.js index 35dbf38a42..7f6fe6a4b7 100644 --- a/public/src/forum/topic/threadTools.js +++ b/public/src/forum/topic/threadTools.js @@ -21,53 +21,48 @@ define(['forum/topic/fork', 'forum/topic/move'], function(fork, move) { ThreadTools.setPinnedState({tid: tid, isPinned: true}); } - if (ajaxify.variables.get('expose_tools') === '1') { + $('.delete_thread').on('click', function(e) { + var command = threadState.deleted !== '1' ? 'delete' : 'restore'; - $('.thread-tools').removeClass('hide'); - - $('.delete_thread').on('click', function(e) { - var command = threadState.deleted !== '1' ? 'delete' : 'restore'; - - translator.translate('[[topic:thread_tools.' + command + '_confirm]]', function(msg) { - bootbox.confirm(msg, function(confirm) { - if (confirm) { - socket.emit('topics.' + command, [tid]); - } - }); + translator.translate('[[topic:thread_tools.' + command + '_confirm]]', function(msg) { + bootbox.confirm(msg, function(confirm) { + if (confirm) { + socket.emit('topics.' + command, [tid]); + } }); - - return false; }); - $('.lock_thread').on('click', function(e) { - socket.emit(threadState.locked !== '1' ? 'topics.lock' : 'topics.unlock', [tid]); - return false; - }); + return false; + }); - $('.pin_thread').on('click', function(e) { - socket.emit(threadState.pinned !== '1' ? 'topics.pin' : 'topics.unpin', [tid]); - return false; - }); + $('.lock_thread').on('click', function(e) { + socket.emit(threadState.locked !== '1' ? 'topics.lock' : 'topics.unlock', [tid]); + return false; + }); - $('.markAsUnreadForAll').on('click', function() { - var btn = $(this); - socket.emit('topics.markAsUnreadForAll', [tid], function(err) { - if(err) { - return app.alertError(err.message); - } - app.alertSuccess('[[topic:markAsUnreadForAll.success]]'); - btn.parents('.thread-tools.open').find('.dropdown-toggle').trigger('click'); - }); - return false; - }); + $('.pin_thread').on('click', function(e) { + socket.emit(threadState.pinned !== '1' ? 'topics.pin' : 'topics.unpin', [tid]); + return false; + }); - $('.move_thread').on('click', function(e) { - move.init([tid], ajaxify.variables.get('category_id')); - return false; + $('.markAsUnreadForAll').on('click', function() { + var btn = $(this); + socket.emit('topics.markAsUnreadForAll', [tid], function(err) { + if(err) { + return app.alertError(err.message); + } + app.alertSuccess('[[topic:markAsUnreadForAll.success]]'); + btn.parents('.thread-tools.open').find('.dropdown-toggle').trigger('click'); }); + return false; + }); - fork.init(); - } + $('.move_thread').on('click', function(e) { + move.init([tid], ajaxify.variables.get('category_id')); + return false; + }); + + fork.init(); socket.emit('topics.followCheck', tid, function(err, state) { setFollowState(state); diff --git a/src/controllers/topics.js b/src/controllers/topics.js index b16541afc7..ed70e7fe38 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -10,27 +10,27 @@ var topicsController = {}, meta = require('./../meta'), topics = require('./../topics'), posts = require('../posts'), - threadTools = require('./../threadTools'), + privileges = require('../privileges'), utils = require('./../../public/src/utils'); topicsController.get = function(req, res, next) { var tid = req.params.topic_id, page = req.query.page || 1, uid = req.user ? req.user.uid : 0, - privileges; + userPrivileges; async.waterfall([ function(next) { - threadTools.privileges(tid, uid, function(err, userPrivileges) { + privileges.topics.get(tid, uid, function(err, privileges) { if (err) { return next(err); } - if (!userPrivileges.meta.read) { + if (!privileges.meta.read) { return next(new Error('[[error:no-privileges]]')); } - privileges = userPrivileges; + userPrivileges = privileges; next(); }); }, @@ -45,7 +45,7 @@ topicsController.get = function(req, res, next) { topics.getTopicWithPosts(tid, uid, start, end, function (err, topicData) { if (topicData) { - if (parseInt(topicData.deleted, 10) === 1 && parseInt(topicData.expose_tools, 10) === 0) { + if (parseInt(topicData.deleted, 10) === 1 && !userPrivileges.view_deleted) { return next(new Error('[[error:no-topic]]')); } topicData.currentPage = page; @@ -154,7 +154,7 @@ topicsController.get = function(req, res, next) { } } - data.privileges = privileges; + data.privileges = userPrivileges; var topic_url = tid + (req.params.slug ? '/' + req.params.slug : ''); var queryString = qs.stringify(req.query); diff --git a/src/privileges.js b/src/privileges.js index 275db8b724..e93584b727 100644 --- a/src/privileges.js +++ b/src/privileges.js @@ -2,7 +2,8 @@ var privileges = {}; +require('./privileges/categories')(privileges); +require('./privileges/topics')(privileges); require('./privileges/posts')(privileges); - module.exports = privileges; \ No newline at end of file diff --git a/src/privileges/categories.js b/src/privileges/categories.js new file mode 100644 index 0000000000..aa1b7d233f --- /dev/null +++ b/src/privileges/categories.js @@ -0,0 +1,28 @@ + +'use strict'; + +var async = require('async'), + + user = require('../user'), + helpers = require('./helpers'); + + +module.exports = function(privileges) { + + privileges.categories = {}; + + privileges.categories.canRead = function(cid, uid, callback) { + helpers.some([ + function(next) { + helpers.allowedTo('read', uid, cid, next); + }, + function(next) { + user.isModerator(uid, cid, next); + }, + function(next) { + user.isAdministrator(uid, next); + } + ], callback); + }; + +}; diff --git a/src/privileges/helpers.js b/src/privileges/helpers.js index 1739fccba3..dcaa0c9b76 100644 --- a/src/privileges/helpers.js +++ b/src/privileges/helpers.js @@ -10,6 +10,16 @@ var async = require('async'), var helpers = {}; +helpers.some = function(tasks, callback) { + async.some(tasks, function(task, next) { + task(function(err, result) { + next(!err && result); + }); + }, function(result) { + callback(null, result); + }); +}; + helpers.allowedTo = function(privilege, uid, cid, callback) { categories.getCategoryField(cid, 'disabled', function(err, disabled) { if (err) { @@ -47,7 +57,7 @@ function isMember(method, group, uid, callback) { return callback(null, null); } - method(group, uid, callback); + method(uid, group, callback); }); } diff --git a/src/privileges/posts.js b/src/privileges/posts.js index 8894dd1509..d3501f218c 100644 --- a/src/privileges/posts.js +++ b/src/privileges/posts.js @@ -59,28 +59,12 @@ module.exports = function(privileges) { 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.categories.canRead(cid, uid, callback); }); }; privileges.posts.canEdit = function(pid, uid, callback) { - async.some([ + helpers.some([ function(next) { posts.isOwner(pid, uid, next); }, @@ -101,12 +85,22 @@ module.exports = function(privileges) { function(next) { user.isAdministrator(uid, next); } - ], function(task, next) { - task(function(err, result) { - next(!err && result); - }); - }, function(result) { - callback(null, result); - }); + ], callback); + }; + + privileges.posts.canMove = function(pid, uid, callback) { + helpers.some([ + function(next) { + posts.getCidByPid(pid, function(err, cid) { + if (err) { + return next(err); + } + user.isModerator(uid, cid, next); + }); + }, + function(next) { + user.isAdministrator(uid, next); + } + ], callback); }; }; diff --git a/src/privileges/topics.js b/src/privileges/topics.js new file mode 100644 index 0000000000..3b662c3057 --- /dev/null +++ b/src/privileges/topics.js @@ -0,0 +1,122 @@ + +'use strict'; + +var async = require('async'), + + topics = require('../topics'), + user = require('../user'), + helpers = require('./helpers'), + groups = require('../groups'), + categories = require('../categories'); + +module.exports = function(privileges) { + + privileges.topics = {}; + + privileges.topics.get = function(tid, uid, callback) { + + topics.getTopicField(tid, 'cid', function(err, cid) { + if (err) { + return callback(err); + } + + async.parallel({ + 'topics:reply': function(next) { + helpers.allowedTo('topics:reply', uid, cid, next); + }, + read: function(next) { + helpers.allowedTo('read', uid, cid, next); + }, + manage_topic: function(next) { + helpers.hasEnoughReputationFor('privileges:manage_topic', uid, 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 || results.manage_topic; + + callback(null, { + meta: { + 'topics:reply': results['topics:reply'], + editable: editable, + view_deleted: editable, + read: results.read + } + }); + }); + }); + }; + + privileges.topics.canRead = function(tid, uid, callback) { + topics.getTopicField(tid, 'cid', function(err, cid) { + if (err) { + return callback(err); + } + + privileges.categories.canRead(cid, uid, callback); + }); + }; + + privileges.topics.canReply = function(tid, uid, callback) { + topics.getTopicField(tid, 'cid', function(err, cid) { + if (err) { + return callback(err); + } + + helpers.some([ + function(next) { + helpers.allowedTo('topics:reply', uid, cid, next); + }, + function(next) { + user.isModerator(uid, cid, next); + }, + function(next) { + user.isAdministrator(uid, next); + } + ], callback); + }); + }; + + privileges.topics.canEdit = function(tid, uid, callback) { + helpers.some([ + function(next) { + helpers.hasEnoughReputationFor('privileges:manage_topic', uid, next); + }, + function(next) { + topics.getTopicField(tid, 'cid', function(err, cid) { + if (err) { + return next(err); + } + user.isModerator(uid, cid, next); + }); + }, + function(next) { + user.isAdministrator(uid, next); + } + ], callback); + }; + + privileges.topics.canMove = function(tid, uid, callback) { + helpers.some([ + function(next) { + topics.getTopicField(tid, 'cid', function(err, cid) { + if (err) { + return next(err); + } + user.isModerator(uid, cid, next); + }); + }, + function(next) { + user.isAdministrator(uid, next); + } + ], callback); + }; +}; diff --git a/src/routes/feeds.js b/src/routes/feeds.js index b42db1b3b3..3b1fc298ef 100644 --- a/src/routes/feeds.js +++ b/src/routes/feeds.js @@ -7,30 +7,29 @@ var posts = require('./../posts'), rss = require('rss'), nconf = require('nconf'), - ThreadTools = require('./../threadTools'), - CategoryTools = require('./../categoryTools'); + privileges = require('../privileges'); function hasTopicPrivileges(req, res, next) { var tid = req.params.topic_id; - hasPrivileges(ThreadTools, tid, req, res, next); + hasPrivileges(privileges.topics.canRead, tid, req, res, next); } function hasCategoryPrivileges(req, res, next) { var cid = req.params.category_id; - hasPrivileges(CategoryTools, cid, req, res, next); + hasPrivileges(privileges.categories.canRead, cid, req, res, next); } -function hasPrivileges(module, id, req, res, next) { +function hasPrivileges(method, id, req, res, next) { var uid = req.user ? req.user.uid || 0 : 0; - module.privileges(id, uid, function(err, privileges) { - if(err) { + method(id, uid, function(err, canRead) { + if (err) { return next(err); } - if(!privileges.read) { + if (!canRead) { return res.redirect('403'); } @@ -66,7 +65,7 @@ function generateForTopic(req, res, next) { } topicData.posts.forEach(function(postData) { - if (parseInt(postData.deleted, 10) === 0) { + if (!postData.deleted) { dateStamp = new Date(parseInt(parseInt(postData.edited, 10) === 0 ? postData.timestamp : postData.edited, 10)).toUTCString(); feed.item({ diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 278a1ab2d3..1d240140f6 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -37,8 +37,15 @@ SocketPosts.reply = function(socket, data, callback) { } if (postData) { + var privileges = { + meta : { + 'topics:reply': true + } + }; + websockets.server.sockets.emit('event:new_post', { - posts: [postData] + posts: [postData], + privileges: privileges }); module.parent.exports.emitTopicPostStats(); diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index 7971635410..2da898dc35 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -3,6 +3,7 @@ var topics = require('../topics'), categories = require('../categories'), + privileges = require('../privileges'), threadTools = require('../threadTools'), categoryTools = require('../categoryTools'), websockets = require('./index'), @@ -181,12 +182,12 @@ function doTopicAction(action, socket, tids, callback) { } async.each(tids, function(tid, next) { - threadTools.privileges(tid, socket.uid, function(err, privileges) { + privileges.topics.canEdit(tid, socket.uid, function(err, canEdit) { if(err) { return next(err); } - if(!privileges || !privileges.meta.editable) { + if(!canEdit) { return next(new Error('[[error:no-privileges]]')); } @@ -210,21 +211,17 @@ SocketTopics.createTopicFromPosts = function(socket, data, callback) { }; SocketTopics.movePost = function(socket, data, callback) { - if(!socket.uid) { + if (!socket.uid) { return callback(new Error('[[error:not-logged-in]]')); } - if(!data || !data.pid || !data.tid) { + if (!data || !data.pid || !data.tid) { return callback(new Error('[[error:invalid-data]]')); } - threadTools.privileges(data.tid, socket.uid, function(err, privileges) { - if(err) { - return callback(err); - } - - if(!(privileges.admin || privileges.moderator)) { - return callback(new Error('[[error:no-privileges]]')); + privileges.posts.canMove(data.tid, socket.uid, function(err, canMove) { + if (err || !canMove) { + return callback(err || new Error('[[error:no-privileges]]')); } topics.movePostToTopic(data.pid, data.tid, callback); @@ -240,10 +237,10 @@ SocketTopics.move = function(socket, data, callback) { var oldCid; async.waterfall([ function(next) { - threadTools.privileges(tid, socket.uid, next); + privileges.topics.canMove(tid, socket.uid, next); }, - function(privileges, next) { - if(!(privileges.admin || privileges.moderator)) { + function(canMove, next) { + if (!canMove) { return next(new Error('[[error:no-privileges]]')); } next(); @@ -336,7 +333,7 @@ SocketTopics.loadMore = function(socket, data, callback) { topics.getTopicPosts(data.tid, start, end, socket.uid, false, next); }, privileges: function(next) { - threadTools.privileges(data.tid, socket.uid, next); + privileges.topics.get(data.tid, socket.uid, next); } }, callback); }); diff --git a/src/threadTools.js b/src/threadTools.js index 72d5a5d13e..8b13cb6dfd 100644 --- a/src/threadTools.js +++ b/src/threadTools.js @@ -23,38 +23,6 @@ var winston = require('winston'), db.isSortedSetMember('topics:tid', tid, callback); }; - ThreadTools.privileges = function(tid, uid, callback) { - async.parallel({ - categoryPrivs: function(next) { - topics.getTopicField(tid, 'cid', function(err, cid) { - CategoryTools.privileges(cid, uid, next); - }); - }, - 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_topic'], 10)); - }); - } - } - }, function(err, results) { - if (err) { - return callback(err); - } - - var privileges = results.categoryPrivs; - privileges.meta.editable = privileges.meta.editable || results.hasEnoughRep; - privileges.meta.view_deleted = privileges.meta.view_deleted || results.hasEnoughRep; - - callback(null, privileges); - }); - }; - ThreadTools.delete = function(tid, uid, callback) { toggleDelete(tid, uid, true, callback); }; diff --git a/src/topics.js b/src/topics.js index 6f31c817ca..478d76066c 100644 --- a/src/topics.js +++ b/src/topics.js @@ -11,7 +11,8 @@ var async = require('async'), user = require('./user'), categories = require('./categories'), categoryTools = require('./categoryTools'), - threadTools = require('./threadTools'); + threadTools = require('./threadTools'), + privileges = require('./privileges'); (function(Topics) { @@ -132,8 +133,8 @@ var async = require('async'), } async.filter(tids, function(tid, next) { - threadTools.privileges(tid, uid, function(err, privileges) { - next(!err && privileges.meta.read); + privileges.topics.canRead(tid, uid, function(err, canRead) { + next(!err && canRead); }); }, function(tids) { Topics.getTopicsByTids(tids, uid, function(err, topicData) { @@ -269,9 +270,6 @@ var async = require('async'), posts: function(next) { Topics.getTopicPosts(tid, start, end, uid, false, next); }, - privileges: function(next) { - threadTools.privileges(tid, uid, next); - }, category: function(next) { Topics.getCategoryData(tid, next); }, @@ -291,7 +289,6 @@ var async = require('async'), topicData.thread_tools = results.threadTools; topicData.pageCount = results.pageCount; topicData.unreplied = parseInt(topicData.postcount, 10) === 1; - topicData.expose_tools = results.privileges.meta.editable ? 1 : 0; callback(null, topicData); }); diff --git a/src/topics/create.js b/src/topics/create.js index 454ea14d28..9c95c65c66 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -9,6 +9,7 @@ var async = require('async'), meta = require('./../meta'), posts = require('./../posts'), threadTools = require('./../threadTools'), + privileges = require('../privileges'), categoryTools = require('./../categoryTools'); module.exports = function(Topics) { @@ -144,7 +145,6 @@ module.exports = function(Topics) { uid = data.uid, toPid = data.toPid, content = data.content, - privileges, postData; async.waterfall([ @@ -173,11 +173,10 @@ module.exports = function(Topics) { return next(new Error('[[error:topic-locked]]')); } - threadTools.privileges(tid, uid, next); + privileges.topics.canReply(tid, uid, next); }, - function(privilegesData, next) { - privileges = privilegesData; - if (!privileges.meta['topics:reply']) { + function(canReply, next) { + if (!canReply) { return next(new Error('[[error:no-privileges]]')); } next(); @@ -232,7 +231,8 @@ module.exports = function(Topics) { postData.favourited = false; postData.votes = 0; postData.display_moderator_tools = true; - postData.display_move_tools = privileges.admin || privileges.moderator; + postData.display_move_tools = true; + postData.selfPost = false; postData.relativeTime = utils.toISOString(postData.timestamp); next(null, postData); diff --git a/src/topics/unread.js b/src/topics/unread.js index 375d921921..4f153cf227 100644 --- a/src/topics/unread.js +++ b/src/topics/unread.js @@ -8,7 +8,7 @@ var async = require('async'), user = require('./../user'), notifications = require('./../notifications'), categories = require('./../categories'), - threadTools = require('./../threadTools'); + privileges = require('../privileges'); module.exports = function(Topics) { @@ -49,8 +49,8 @@ module.exports = function(Topics) { }); async.filter(newtids, function(tid, next) { - threadTools.privileges(tid, uid, function(err, privileges) { - next(!err && privileges.meta.read); + privileges.topics.canRead(tid, uid, function(err, canRead) { + next(!err && canRead); }); }, function(newtids) { unreadTids.push.apply(unreadTids, newtids);