diff --git a/src/categories/create.js b/src/categories/create.js index 9cd698b6f3..a766ea0204 100644 --- a/src/categories/create.js +++ b/src/categories/create.js @@ -61,6 +61,8 @@ module.exports = function (Categories) { 'topics:tag', 'posts:edit', 'posts:delete', + 'posts:upvote', + 'posts:downvote', 'topics:delete', ]; diff --git a/src/groups/create.js b/src/groups/create.js index c720923ca7..a8297b946b 100644 --- a/src/groups/create.js +++ b/src/groups/create.js @@ -90,11 +90,11 @@ module.exports = function (Groups) { return callback(new Error('[[error:group-name-too-long]]')); } - if (!Groups.isPrivilegeGroup(name) && name.indexOf(':') !== -1) { + if (!Groups.isPrivilegeGroup(name) && name.includes(':')) { return callback(new Error('[[error:invalid-group-name]]')); } - if (name.indexOf('/') !== -1 || !utils.slugify(name)) { + if (name.includes('/') || !utils.slugify(name)) { return callback(new Error('[[error:invalid-group-name]]')); } diff --git a/src/posts/votes.js b/src/posts/votes.js index f7fdde759e..529fcbd0c3 100644 --- a/src/posts/votes.js +++ b/src/posts/votes.js @@ -6,6 +6,7 @@ var meta = require('../meta'); var db = require('../database'); var user = require('../user'); var plugins = require('../plugins'); +var privileges = require('../privileges'); module.exports = function (Posts) { var votesInProgress = {}; @@ -15,16 +16,27 @@ module.exports = function (Posts) { return callback(new Error('[[error:reputation-system-disabled]]')); } - if (voteInProgress(pid, uid)) { - return callback(new Error('[[error:already-voting-for-this-post]]')); - } + async.waterfall([ + function (next) { + privileges.posts.can('posts:upvote', pid, uid, next); + }, + function (canUpvote, next) { + if (!canUpvote) { + return next(new Error('[[error:no-privileges]]')); + } - putVoteInProgress(pid, uid); + if (voteInProgress(pid, uid)) { + return next(new Error('[[error:already-voting-for-this-post]]')); + } - toggleVote('upvote', pid, uid, function (err, data) { - clearVoteProgress(pid, uid); - callback(err, data); - }); + putVoteInProgress(pid, uid); + + toggleVote('upvote', pid, uid, function (err, data) { + clearVoteProgress(pid, uid); + next(err, data); + }); + }, + ], callback); }; Posts.downvote = function (pid, uid, callback) { @@ -36,16 +48,27 @@ module.exports = function (Posts) { return callback(new Error('[[error:downvoting-disabled]]')); } - if (voteInProgress(pid, uid)) { - return callback(new Error('[[error:already-voting-for-this-post]]')); - } + async.waterfall([ + function (next) { + privileges.posts.can('posts:downvote', pid, uid, next); + }, + function (canUpvote, next) { + if (!canUpvote) { + return next(new Error('[[error:no-privileges]]')); + } - putVoteInProgress(pid, uid); + if (voteInProgress(pid, uid)) { + return next(new Error('[[error:already-voting-for-this-post]]')); + } - toggleVote('downvote', pid, uid, function (err, data) { - clearVoteProgress(pid, uid); - callback(err, data); - }); + putVoteInProgress(pid, uid); + + toggleVote('downvote', pid, uid, function (err, data) { + clearVoteProgress(pid, uid); + next(err, data); + }); + }, + ], callback); }; Posts.unvote = function (pid, uid, callback) { @@ -106,7 +129,7 @@ module.exports = function (Posts) { }; function voteInProgress(pid, uid) { - return Array.isArray(votesInProgress[uid]) && votesInProgress[uid].indexOf(parseInt(pid, 10)) !== -1; + return Array.isArray(votesInProgress[uid]) && votesInProgress[uid].includes(parseInt(pid, 10)); } function putVoteInProgress(pid, uid) { diff --git a/src/privileges.js b/src/privileges.js index 64d16d3e5c..b42a20e13c 100644 --- a/src/privileges.js +++ b/src/privileges.js @@ -11,6 +11,8 @@ privileges.privilegeLabels = [ { name: 'Tag Topics' }, { name: 'Edit Posts' }, { name: 'Delete Posts' }, + { name: 'Upvote Posts' }, + { name: 'Downvote Posts' }, { name: 'Delete Topics' }, { name: 'Purge' }, { name: 'Moderate' }, @@ -25,6 +27,8 @@ privileges.userPrivilegeList = [ 'topics:tag', 'posts:edit', 'posts:delete', + 'posts:upvote', + 'posts:downvote', 'topics:delete', 'purge', 'moderate', diff --git a/src/upgrades/1.8.0/vote_privilege.js b/src/upgrades/1.8.0/vote_privilege.js new file mode 100644 index 0000000000..03f79280ef --- /dev/null +++ b/src/upgrades/1.8.0/vote_privilege.js @@ -0,0 +1,22 @@ +'use strict'; + + +var async = require('async'); + +var privileges = require('../../privileges'); +var db = require('../../database'); + +module.exports = { + name: 'Give vote privilege to registered-users on all categories', + timestamp: Date.UTC(2018, 0, 9), + method: function (callback) { + db.getSortedSetRange('categories:cid', 0, -1, function (err, cids) { + if (err) { + return callback(err); + } + async.eachSeries(cids, function (cid, next) { + privileges.categories.give(['posts:upvote', 'posts:downvote'], cid, 'registered-users', next); + }, callback); + }); + }, +}; diff --git a/src/views/admin/partials/categories/privileges.tpl b/src/views/admin/partials/categories/privileges.tpl index c240c05a63..c5bfc3ec63 100644 --- a/src/views/admin/partials/categories/privileges.tpl +++ b/src/views/admin/partials/categories/privileges.tpl @@ -5,7 +5,7 @@ [[admin/manage/categories:privileges.section-viewing]] - + [[admin/manage/categories:privileges.section-posting]] @@ -61,7 +61,7 @@ [[admin/manage/categories:privileges.section-viewing]] - + [[admin/manage/categories:privileges.section-posting]] diff --git a/test/categories.js b/test/categories.js index c1869652f7..90198f91b4 100644 --- a/test/categories.js +++ b/test/categories.js @@ -651,6 +651,8 @@ describe('Categories', function () { 'topics:tag': false, 'topics:delete': false, 'posts:edit': false, + 'posts:upvote': false, + 'posts:downvote': false, purge: false, moderate: false, }); @@ -678,6 +680,8 @@ describe('Categories', function () { assert.deepEqual(data, { 'groups:find': true, 'groups:posts:edit': true, + 'groups:posts:upvote': true, + 'groups:posts:downvote': true, 'groups:topics:delete': false, 'groups:topics:create': true, 'groups:topics:reply': true, diff --git a/test/posts.js b/test/posts.js index 3643454148..84114d0a91 100644 --- a/test/posts.js +++ b/test/posts.js @@ -72,6 +72,22 @@ describe('Post\'s', function () { }); describe('voting', function () { + it('should fail to upvote post if group does not have upvote permission', function (done) { + privileges.categories.rescind(['posts:upvote', 'posts:downvote'], cid, 'registered-users', function (err) { + assert.ifError(err); + socketPosts.upvote({ uid: voterUid }, { pid: postData.pid, room_id: 'topic_1' }, function (err) { + assert.equal(err.message, '[[error:no-privileges]]'); + socketPosts.downvote({ uid: voterUid }, { pid: postData.pid, room_id: 'topic_1' }, function (err) { + assert.equal(err.message, '[[error:no-privileges]]'); + privileges.categories.give(['posts:upvote', 'posts:downvote'], cid, 'registered-users', function (err) { + assert.ifError(err); + done(); + }); + }); + }); + }); + }); + it('should upvote a post', function (done) { socketPosts.upvote({ uid: voterUid }, { pid: postData.pid, room_id: 'topic_1' }, function (err, result) { assert.ifError(err);