diff --git a/install/package.json b/install/package.json index c5b8cab9b4..e8fa9735fc 100644 --- a/install/package.json +++ b/install/package.json @@ -59,7 +59,7 @@ "morgan": "^1.9.0", "mousetrap": "^1.6.1", "nconf": "^0.9.1", - "nodebb-plugin-composer-default": "6.0.7", + "nodebb-plugin-composer-default": "6.0.8", "nodebb-plugin-dbsearch": "2.0.9", "nodebb-plugin-emoji": "2.0.9", "nodebb-plugin-emoji-android": "2.0.0", diff --git a/src/categories/create.js b/src/categories/create.js index d4a74084d9..9cd698b6f3 100644 --- a/src/categories/create.js +++ b/src/categories/create.js @@ -62,7 +62,6 @@ module.exports = function (Categories) { 'posts:edit', 'posts:delete', 'topics:delete', - 'upload:post:image', ]; async.series([ diff --git a/src/controllers/accounts/chats.js b/src/controllers/accounts/chats.js index d717f6267a..ff5a07d157 100644 --- a/src/controllers/accounts/chats.js +++ b/src/controllers/accounts/chats.js @@ -20,12 +20,6 @@ chatsController.get = function (req, res, callback) { async.waterfall([ function (next) { - privileges.global.can('chat', req.uid, next); - }, - function (canChat, next) { - if (!canChat) { - return next(new Error('[[error:no-privileges]]')); - } user.getUidByUserslug(req.params.userslug, next); }, function (_uid, next) { @@ -33,6 +27,13 @@ chatsController.get = function (req, res, callback) { if (!uid) { return callback(); } + + privileges.global.can('chat', req.uid, next); + }, + function (canChat, next) { + if (!canChat) { + return next(new Error('[[error:no-privileges]]')); + } messaging.getRecentChats(req.uid, uid, 0, 19, next); }, function (_recentChats, next) { diff --git a/src/controllers/uploads.js b/src/controllers/uploads.js index 0a91cd5dcc..e7e77c4a4f 100644 --- a/src/controllers/uploads.js +++ b/src/controllers/uploads.js @@ -37,9 +37,6 @@ uploadsController.upload = function (req, res, filesIterator) { uploadsController.uploadPost = function (req, res, next) { uploadsController.upload(req, res, function (uploadedFile, next) { - if (!parseInt(req.body.cid, 10)) { - return next(new Error('[[error:category-not-selected]]')); - } var isImage = uploadedFile.type.match(/image./); if (isImage) { uploadAsImage(req, uploadedFile, next); @@ -52,7 +49,7 @@ uploadsController.uploadPost = function (req, res, next) { function uploadAsImage(req, uploadedFile, callback) { async.waterfall([ function (next) { - privileges.categories.can('upload:post:image', req.body.cid, req.uid, next); + privileges.global.can('upload:post:image', req.uid, next); }, function (canUpload, next) { if (!canUpload) { @@ -82,7 +79,7 @@ function uploadAsImage(req, uploadedFile, callback) { function uploadAsFile(req, uploadedFile, callback) { async.waterfall([ function (next) { - privileges.categories.can('upload:post:file', req.body.cid, req.uid, next); + privileges.global.can('upload:post:file', req.uid, next); }, function (canUpload, next) { if (!canUpload) { diff --git a/src/install.js b/src/install.js index e9e8eecb49..2906adc9e8 100644 --- a/src/install.js +++ b/src/install.js @@ -354,8 +354,8 @@ function createGlobalModeratorsGroup(next) { } function giveGlobalPrivileges(next) { - var groups = require('./groups'); - groups.join('cid:0:privileges:groups:chat', 'registered-users', next); + var privileges = require('./privileges'); + privileges.global.give(['chat', 'upload:post:image'], 'registered-users', next); } function createCategories(next) { diff --git a/src/middleware/header.js b/src/middleware/header.js index ae245ce78f..a0cf65d396 100644 --- a/src/middleware/header.js +++ b/src/middleware/header.js @@ -78,8 +78,8 @@ module.exports = function (middleware) { isModerator: function (next) { user.isModeratorOfAnyCategory(req.uid, next); }, - canChat: function (next) { - privileges.global.can('chat', req.uid, next); + privileges: function (next) { + privileges.global.get(req.uid, next); }, user: function (next) { var userData = { @@ -136,6 +136,7 @@ module.exports = function (middleware) { results.user.isAdmin = results.isAdmin; results.user.isGlobalMod = results.isGlobalMod; results.user.isMod = !!results.isModerator; + results.user.privileges = results.privileges; results.user.uid = parseInt(results.user.uid, 10); results.user.email = String(results.user.email); diff --git a/src/privileges.js b/src/privileges.js index b4da9f8e88..64d16d3e5c 100644 --- a/src/privileges.js +++ b/src/privileges.js @@ -12,8 +12,6 @@ privileges.privilegeLabels = [ { name: 'Edit Posts' }, { name: 'Delete Posts' }, { name: 'Delete Topics' }, - { name: 'Upload Images' }, - { name: 'Upload Files' }, { name: 'Purge' }, { name: 'Moderate' }, ]; @@ -28,8 +26,6 @@ privileges.userPrivilegeList = [ 'posts:edit', 'posts:delete', 'topics:delete', - 'upload:post:image', - 'upload:post:file', 'purge', 'moderate', ]; diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 610ff7b711..60822c4e46 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -198,19 +198,13 @@ module.exports = function (privileges) { }; privileges.categories.give = function (privileges, cid, groupName, callback) { - giveOrRescind(groups.join, privileges, cid, groupName, callback); + helpers.giveOrRescind(groups.join, privileges, cid, groupName, callback); }; privileges.categories.rescind = function (privileges, cid, groupName, callback) { - giveOrRescind(groups.leave, privileges, cid, groupName, callback); + helpers.giveOrRescind(groups.leave, privileges, cid, groupName, callback); }; - function giveOrRescind(method, privileges, cid, groupName, callback) { - async.eachSeries(privileges, function (privilege, next) { - method('cid:' + cid + ':privileges:groups:' + privilege, groupName, next); - }, callback); - } - privileges.categories.canMoveAllTopics = function (currentCid, targetCid, uid, callback) { async.waterfall([ function (next) { diff --git a/src/privileges/global.js b/src/privileges/global.js index bf86029ac0..f1f88c4fff 100644 --- a/src/privileges/global.js +++ b/src/privileges/global.js @@ -2,8 +2,10 @@ 'use strict'; var async = require('async'); +var _ = require('lodash'); var user = require('../user'); +var groups = require('../groups'); var helpers = require('./helpers'); var plugins = require('../plugins'); @@ -12,10 +14,14 @@ module.exports = function (privileges) { privileges.global.privilegeLabels = [ { name: 'Chat' }, + { name: 'Upload Images' }, + { name: 'Upload Files' }, ]; privileges.global.userPrivilegeList = [ 'chat', + 'upload:post:image', + 'upload:post:file', ]; privileges.global.groupPrivilegeList = privileges.global.userPrivilegeList.map(function (privilege) { @@ -48,6 +54,34 @@ module.exports = function (privileges) { ], callback); }; + privileges.global.get = function (uid, callback) { + async.waterfall([ + function (next) { + async.parallel({ + privileges: function (next) { + helpers.isUserAllowedTo(privileges.global.userPrivilegeList, uid, 0, next); + }, + isAdministrator: function (next) { + user.isAdministrator(uid, next); + }, + isGlobalModerator: function (next) { + user.isGlobalModerator(uid, next); + }, + }, next); + }, + function (results, next) { + var privData = _.zipObject(privileges.global.userPrivilegeList, results.privileges); + var isAdminOrMod = results.isAdministrator || results.isGlobalModerator; + + plugins.fireHook('filter:privileges.global.get', { + chat: privData.chat || isAdminOrMod, + 'upload:post:image': privData['upload:post:image'] || isAdminOrMod, + 'upload:post:file': privData['upload:post:file'] || isAdminOrMod, + }, next); + }, + ], callback); + }; + privileges.global.can = function (privilege, uid, callback) { helpers.some([ function (next) { @@ -63,4 +97,32 @@ module.exports = function (privileges) { }, ], callback); }; + + privileges.global.give = function (privileges, groupName, callback) { + helpers.giveOrRescind(groups.join, privileges, 0, groupName, callback); + }; + + privileges.global.rescind = function (privileges, groupName, callback) { + helpers.giveOrRescind(groups.leave, privileges, 0, groupName, callback); + }; + + privileges.global.userPrivileges = function (uid, callback) { + var tasks = {}; + + privileges.global.userPrivilegeList.forEach(function (privilege) { + tasks[privilege] = async.apply(groups.isMember, uid, 'cid:0:privileges:' + privilege); + }); + + async.parallel(tasks, callback); + }; + + privileges.global.groupPrivileges = function (groupName, callback) { + var tasks = {}; + + privileges.global.groupPrivilegeList.forEach(function (privilege) { + tasks[privilege] = async.apply(groups.isMember, groupName, 'cid:0:privileges:' + privilege); + }); + + async.parallel(tasks, callback); + }; }; diff --git a/src/privileges/helpers.js b/src/privileges/helpers.js index 5a1218ae19..c3452c495e 100644 --- a/src/privileges/helpers.js +++ b/src/privileges/helpers.js @@ -221,3 +221,9 @@ helpers.getGroupPrivileges = function (cid, hookName, groupPrivilegeList, callba }, ], callback); }; + +helpers.giveOrRescind = function (method, privileges, cid, groupName, callback) { + async.eachSeries(privileges, function (privilege, next) { + method('cid:' + cid + ':privileges:groups:' + privilege, groupName, next); + }, callback); +}; diff --git a/src/upgrades/1.8.0/global_upload_privilege.js b/src/upgrades/1.8.0/global_upload_privilege.js new file mode 100644 index 0000000000..22473a9ee0 --- /dev/null +++ b/src/upgrades/1.8.0/global_upload_privilege.js @@ -0,0 +1,45 @@ +'use strict'; + + +var async = require('async'); +var groups = require('../../groups'); +var privileges = require('../../privileges'); +var db = require('../../database'); + +module.exports = { + name: 'Give upload privilege to registered-users globally if it is given on a category', + timestamp: Date.UTC(2018, 0, 3), + method: function (callback) { + db.getSortedSetRange('categories:cid', 0, -1, function (err, cids) { + if (err) { + return callback(err); + } + async.eachSeries(cids, function (cid, next) { + getGroupPrivileges(cid, function (err, groupPrivileges) { + if (err) { + return next(err); + } + + var privs = []; + if (groupPrivileges['groups:upload:post:image']) { + privs.push('upload:post:image'); + } + if (groupPrivileges['groups:upload:post:file']) { + privs.push('upload:post:file'); + } + privileges.global.give(privs, 'registered-users', next); + }); + }, callback); + }); + }, +}; + +function getGroupPrivileges(cid, callback) { + var tasks = {}; + + ['groups:upload:post:image', 'groups:upload:post:file'].forEach(function (privilege) { + tasks[privilege] = async.apply(groups.isMember, 'registered-users', 'cid:' + cid + ':privileges:' + privilege); + }); + + async.parallel(tasks, callback); +} diff --git a/src/views/admin/partials/categories/privileges.tpl b/src/views/admin/partials/categories/privileges.tpl index c5bfc3ec63..c240c05a63 100644 --- a/src/views/admin/partials/categories/privileges.tpl +++ b/src/views/admin/partials/categories/privileges.tpl @@ -5,7 +5,7 @@