diff --git a/src/controllers/admin/postqueue.js b/src/controllers/admin/postqueue.js index 749b4c0a2a..29c56b9f80 100644 --- a/src/controllers/admin/postqueue.js +++ b/src/controllers/admin/postqueue.js @@ -14,31 +14,51 @@ var postQueueController = module.exports; postQueueController.get = function (req, res, next) { var page = parseInt(req.query.page, 10) || 1; var postsPerPage = 20; - var pageCount = 0; - - var start = (page - 1) * postsPerPage; - var stop = start + postsPerPage - 1; - - var postData; - + var results; async.waterfall([ function (next) { async.parallel({ - count: function (next) { - db.sortedSetCard('post:queue', next); - }, ids: function (next) { - db.getSortedSetRange('post:queue', start, stop, next); + db.getSortedSetRange('post:queue', 0, -1, next); + }, + isAdminOrGlobalMod: function (next) { + user.isAdminOrGlobalMod(req.uid, next); + }, + moderatedCids: function (next) { + user.getModeratedCids(req.uid, next); }, }, next); }, - function (results, next) { - pageCount = Math.ceil(results.count / postsPerPage); + function (_results, next) { + results = _results; + getQueuedPosts(results.ids, next); + }, + function (postData) { + postData = postData.filter(function (postData) { + return postData && (results.isAdminOrGlobalMod || results.moderatedCids.includes(String(postData.category.cid))); + }); - var keys = results.ids.map(function (id) { - return 'post:queue:' + id; + var pageCount = Math.max(1, Math.ceil(postData.length / postsPerPage)); + var start = (page - 1) * postsPerPage; + var stop = start + postsPerPage - 1; + postData = postData.slice(start, stop + 1); + + res.render('admin/manage/post-queue', { + title: '[[pages:post-queue]]', + posts: postData, + pagination: pagination.create(page, pageCount), }); + }, + ], next); +}; +function getQueuedPosts(ids, callback) { + var keys = ids.map(function (id) { + return 'post:queue:' + id; + }); + var postData; + async.waterfall([ + function (next) { db.getObjects(keys, next); }, function (data, next) { @@ -80,12 +100,5 @@ postQueueController.get = function (req, res, next) { ], next); }, next); }, - function (postData) { - res.render('admin/manage/post-queue', { - title: '[[pages:post-queue]]', - posts: postData, - pagination: pagination.create(page, pageCount), - }); - }, - ], next); -}; + ], callback); +} diff --git a/src/controllers/globalmods.js b/src/controllers/globalmods.js index 19a5bd02ee..1cae97a4e2 100644 --- a/src/controllers/globalmods.js +++ b/src/controllers/globalmods.js @@ -4,7 +4,6 @@ var async = require('async'); var user = require('../user'); var adminBlacklistController = require('./admin/blacklist'); -var adminPostQueueController = require('./admin/postqueue'); var globalModsController = module.exports; @@ -21,17 +20,3 @@ globalModsController.ipBlacklist = function (req, res, next) { }, ], next); }; - -globalModsController.postQueue = function (req, res, next) { - async.waterfall([ - function (next) { - user.isAdminOrGlobalMod(req.uid, next); - }, - function (isAdminOrGlobalMod, next) { - if (!isAdminOrGlobalMod) { - return next(); - } - adminPostQueueController.get(req, res, next); - }, - ], next); -}; diff --git a/src/controllers/mods.js b/src/controllers/mods.js index f350e1c880..a7cb252c2c 100644 --- a/src/controllers/mods.js +++ b/src/controllers/mods.js @@ -7,6 +7,7 @@ var categories = require('../categories'); var flags = require('../flags'); var analytics = require('../analytics'); var plugins = require('../plugins'); +var adminPostQueueController = require('./admin/postqueue'); var modsController = module.exports; modsController.flags = {}; @@ -136,3 +137,18 @@ modsController.flags.detail = function (req, res, next) { })); }); }; + +modsController.postQueue = function (req, res, next) { + async.waterfall([ + function (next) { + user.isPrivileged(req.uid, next); + }, + function (isPrivileged, next) { + if (!isPrivileged) { + return next(); + } + adminPostQueueController.get(req, res, next); + }, + ], next); +}; + diff --git a/src/posts/queue.js b/src/posts/queue.js index 5419a28d98..553fbb764e 100644 --- a/src/posts/queue.js +++ b/src/posts/queue.js @@ -128,18 +128,12 @@ module.exports = function (Posts) { Posts.submitFromQueue = function (id, callback) { async.waterfall([ function (next) { - db.getObject('post:queue:' + id, next); + getParsedObject(id, next); }, function (data, next) { if (!data) { return callback(); } - try { - data.data = JSON.parse(data.data); - } catch (err) { - return next(err); - } - if (data.type === 'topic') { createTopic(data.data, next); } else if (data.type === 'reply') { @@ -152,6 +146,25 @@ module.exports = function (Posts) { ], callback); }; + function getParsedObject(id, callback) { + async.waterfall([ + function (next) { + db.getObject('post:queue:' + id, next); + }, + function (data, next) { + if (!data) { + return callback(); + } + try { + data.data = JSON.parse(data.data); + } catch (err) { + return next(err); + } + next(null, data); + }, + ], callback); + } + function createTopic(data, callback) { async.waterfall([ function (next) { @@ -184,23 +197,52 @@ module.exports = function (Posts) { Posts.editQueuedContent = function (uid, id, content, callback) { async.waterfall([ function (next) { - user.isAdminOrGlobalMod(uid, next); + Posts.canEditQueue(uid, id, next); }, - function (isAdminOrGlobalMod, next) { - if (!isAdminOrGlobalMod) { + function (canEditQueue, next) { + if (!canEditQueue) { return callback(new Error('[[error:no-privileges]]')); } - db.getObject('post:queue:' + id, next); + getParsedObject(id, next); }, function (data, next) { - try { - data.data = JSON.parse(data.data); - } catch (err) { - return next(err); + if (!data) { + return callback(); } data.data.content = content; db.setObjectField('post:queue:' + id, 'data', JSON.stringify(data.data), next); }, ], callback); }; + + Posts.canEditQueue = function (uid, id, callback) { + async.waterfall([ + function (next) { + async.parallel({ + isAdminOrGlobalMod: function (next) { + user.isAdminOrGlobalMod(uid, next); + }, + data: function (next) { + getParsedObject(id, next); + }, + }, next); + }, + function (results, next) { + if (results.isAdminOrGlobalMod) { + return callback(null, true); + } + if (!results.data) { + return callback(null, false); + } + if (results.data.type === 'topic') { + next(null, results.data.data.cid); + } else if (results.data.type === 'reply') { + topics.getTopicField(results.data.data.tid, 'cid', next); + } + }, + function (cid, next) { + user.isModerator(uid, cid, next); + }, + ], callback); + }; }; diff --git a/src/routes/index.js b/src/routes/index.js index aabfa51a78..06121c60d6 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -42,10 +42,10 @@ function mainRoutes(app, middleware, controllers) { function modRoutes(app, middleware, controllers) { setupPageRoute(app, '/flags', middleware, [], controllers.mods.flags.list); setupPageRoute(app, '/flags/:flagId', middleware, [], controllers.mods.flags.detail); + setupPageRoute(app, '/post-queue', middleware, [], controllers.mods.postQueue); } function globalModRoutes(app, middleware, controllers) { - setupPageRoute(app, '/post-queue', middleware, [], controllers.globalMods.postQueue); setupPageRoute(app, '/ip-blacklist', middleware, [], controllers.globalMods.ipBlacklist); } diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 3cad4b6db0..39dd1fe64e 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -175,6 +175,7 @@ SocketPosts.accept = function (socket, data, callback) { SocketPosts.reject = function (socket, data, callback) { acceptOrReject(posts.removeFromQueue, socket, data, callback); }; + SocketPosts.editQueuedContent = function (socket, data, callback) { if (!data || !data.id || !data.content) { return callback(new Error('[[error:invalid-data]]')); @@ -185,10 +186,10 @@ SocketPosts.editQueuedContent = function (socket, data, callback) { function acceptOrReject(method, socket, data, callback) { async.waterfall([ function (next) { - user.isAdminOrGlobalMod(socket.uid, next); + posts.canEditQueue(socket.uid, data.id, next); }, - function (isAdminOrGlobalMod, next) { - if (!isAdminOrGlobalMod) { + function (canEditQueue, next) { + if (!canEditQueue) { return callback(new Error('[[error:no-privileges]]')); } diff --git a/test/posts.js b/test/posts.js index a517270e26..3643454148 100644 --- a/test/posts.js +++ b/test/posts.js @@ -831,7 +831,21 @@ describe('Post\'s', function () { }); }); - it('should accept queued posts submit', function (done) { + it('should prevent regular users from approving posts', function (done) { + socketPosts.accept({ uid: uid }, { id: queueId }, function (err) { + assert.equal(err.message, '[[error:no-privileges]]'); + done(); + }); + }); + + it('should prevent regular users from approving non existing posts', function (done) { + socketPosts.accept({ uid: uid }, { id: 123123 }, function (err) { + assert.equal(err.message, '[[error:no-privileges]]'); + done(); + }); + }); + + it('should accept queued posts and submit', function (done) { var ids; async.waterfall([ function (next) { @@ -846,12 +860,5 @@ describe('Post\'s', function () { }, ], done); }); - - it('should prevent regular users from approving posts', function (done) { - socketPosts.accept({ uid: uid }, { id: 1 }, function (err) { - assert.equal(err.message, '[[error:no-privileges]]'); - done(); - }); - }); }); });