diff --git a/public/language/en-GB/admin/manage/privileges.json b/public/language/en-GB/admin/manage/privileges.json index faabb1a7b4..e951ffcfe5 100644 --- a/public/language/en-GB/admin/manage/privileges.json +++ b/public/language/en-GB/admin/manage/privileges.json @@ -1,6 +1,7 @@ { "global": "Global", "global.no-users": "No user-specific global privileges.", + "admin": "Admin", "group-privileges": "Group Privileges", "user-privileges": "User Privileges", "chat": "Chat", @@ -31,5 +32,7 @@ "downvote-posts": "Downvote Posts", "delete-topics": "Delete Topics", "purge": "Purge", - "moderate": "Moderate" + "moderate": "Moderate", + + "manage-categories": "Manage Categories" } \ No newline at end of file diff --git a/public/src/admin/manage/privileges.js b/public/src/admin/manage/privileges.js index 91813b4626..709abcf055 100644 --- a/public/src/admin/manage/privileges.js +++ b/public/src/admin/manage/privileges.js @@ -81,7 +81,13 @@ define('admin/manage/privileges', [ if (err) { return app.alertError(err.message); } - var tpl = cid ? 'admin/partials/categories/privileges' : 'admin/partials/global/privileges'; + + var tpl; + if (cid !== 'admin') { + tpl = cid ? 'admin/partials/privileges/category' : 'admin/partials/privileges/global'; + } else { + tpl = 'admin/partials/privileges/admin'; + } Benchpress.parse(tpl, { privileges: privileges, }, function (html) { @@ -143,7 +149,12 @@ define('admin/manage/privileges', [ inputEl.focus(); autocomplete.user(inputEl, function (ev, ui) { - var defaultPrivileges = cid ? ['find', 'read', 'topics:read'] : ['chat']; + var defaultPrivileges; + if (cid === 'admin') { + defaultPrivileges = ['manage:categories']; + } else { + defaultPrivileges = cid ? ['find', 'read', 'topics:read'] : ['chat']; + } socket.emit('admin.categories.setPrivilege', { cid: cid, privilege: defaultPrivileges, @@ -172,7 +183,14 @@ define('admin/manage/privileges', [ var inputEl = modal.find('input'); autocomplete.group(inputEl, function (ev, ui) { - var defaultPrivileges = cid ? ['groups:find', 'groups:read', 'groups:topics:read'] : ['groups:chat']; + var defaultPrivileges; + if (cid === 'admin') { + defaultPrivileges = ['groups:manage:categories']; + } else { + defaultPrivileges = cid ? ['groups:find', 'groups:read', 'groups:topics:read'] : ['groups:chat']; + } + + console.log(cid, defaultPrivileges); socket.emit('admin.categories.setPrivilege', { cid: cid, privilege: defaultPrivileges, diff --git a/src/controllers/admin/privileges.js b/src/controllers/admin/privileges.js index 687ae3864a..3ebe13d7ec 100644 --- a/src/controllers/admin/privileges.js +++ b/src/controllers/admin/privileges.js @@ -6,9 +6,27 @@ const privileges = require('../../privileges'); const privilegesController = module.exports; privilegesController.get = async function (req, res) { - const cid = req.params.cid ? parseInt(req.params.cid, 10) : 0; + const cid = req.params.cid ? parseInt(req.params.cid, 10) || 'admin' : 0; + + let method; + const type = { + global: false, + admin: false, + cid: false, + }; + if (cid > 0) { + method = privileges.categories.list.bind(null, cid); + type.cid = true; + } else if (cid === 0) { + method = privileges.global.list; + type.global = true; + } else { + method = privileges.admin.list; + type.admin = true; + } + const [privilegesData, categoriesData] = await Promise.all([ - cid ? privileges.categories.list(cid) : privileges.global.list(), + method(), categories.buildForSelectAll(), ]); @@ -17,6 +35,11 @@ privilegesController.get = async function (req, res) { name: '[[admin/manage/privileges:global]]', icon: 'fa-list', }); + categoriesData.unshift({ + cid: 'admin', + name: '[[admin/manage/privileges:admin]]', + icon: 'fa-lock', + }); let selectedCategory; categoriesData.forEach(function (category) { @@ -30,6 +53,7 @@ privilegesController.get = async function (req, res) { }); res.render('admin/manage/privileges', { + type: type, privileges: privilegesData, categories: categoriesData, selectedCategory: selectedCategory, diff --git a/src/groups/create.js b/src/groups/create.js index 76aec0afe0..9ca9d4d2c4 100644 --- a/src/groups/create.js +++ b/src/groups/create.js @@ -73,6 +73,7 @@ module.exports = function (Groups) { } Groups.validateGroupName = function (name) { + console.log(name); if (!name) { throw new Error('[[error:group-name-too-short]]'); } diff --git a/src/groups/index.js b/src/groups/index.js index 231b876c1c..72ba6d0d7a 100644 --- a/src/groups/index.js +++ b/src/groups/index.js @@ -46,7 +46,7 @@ Groups.removeEphemeralGroups = function (groups) { return groups; }; -var isPrivilegeGroupRegex = /^cid:\d+:privileges:[\w:]+$/; +var isPrivilegeGroupRegex = /^cid:(?:\d+|admin):privileges:[\w:]+$/; Groups.isPrivilegeGroup = function (groupName) { return isPrivilegeGroupRegex.test(groupName); }; diff --git a/src/privileges/admin.js b/src/privileges/admin.js new file mode 100644 index 0000000000..5ab6ce80f4 --- /dev/null +++ b/src/privileges/admin.js @@ -0,0 +1,107 @@ + +'use strict'; + +// const _ = require('lodash'); + +// const user = require('../user'); +const groups = require('../groups'); +const helpers = require('./helpers'); +const plugins = require('../plugins'); +const utils = require('../utils'); + +module.exports = function (privileges) { + privileges.admin = {}; + + privileges.admin.privilegeLabels = [ + { name: '[[admin/manage/privileges:manage-categories]]' }, + ]; + + privileges.admin.userPrivilegeList = [ + 'manage:categories', + ]; + + privileges.admin.groupPrivilegeList = privileges.admin.userPrivilegeList.map(privilege => 'groups:' + privilege); + + privileges.admin.list = async function () { + async function getLabels() { + return await utils.promiseParallel({ + users: plugins.fireHook('filter:privileges.admin.list_human', privileges.admin.privilegeLabels.slice()), + groups: plugins.fireHook('filter:privileges.admin.groups.list_human', privileges.admin.privilegeLabels.slice()), + }); + } + const payload = await utils.promiseParallel({ + labels: getLabels(), + users: helpers.getUserPrivileges('admin', 'filter:privileges.admin.list', privileges.admin.userPrivilegeList), + groups: helpers.getGroupPrivileges('admin', 'filter:privileges.admin.groups.list', privileges.admin.groupPrivilegeList), + }); + // This is a hack because I can't do {labels.users.length} to echo the count in templates.js + payload.columnCount = payload.labels.users.length + 2; + return payload; + }; + + // privileges.admin.get = async function (uid) { + // const [userPrivileges, isAdministrator] = await Promise.all([ + // helpers.isUserAllowedTo(privileges.admin.userPrivilegeList, uid, 0), + // user.isAdministrator(uid), + // ]); + + // const privData = _.zipObject(privileges.admin.userPrivilegeList, userPrivileges); + + // return await plugins.fireHook('filter:privileges.admin.get', { + // chat: privData.chat || isAdministrator, + // 'upload:post:image': privData['upload:post:image'] || isAdministrator, + // 'upload:post:file': privData['upload:post:file'] || isAdministrator, + // 'search:content': privData['search:content'] || isAdministrator, + // 'search:users': privData['search:users'] || isAdministrator, + // 'search:tags': privData['search:tags'] || isAdministrator, + // 'view:users': privData['view:users'] || isAdministrator, + // 'view:tags': privData['view:tags'] || isAdministrator, + // 'view:groups': privData['view:groups'] || isAdministrator, + // 'view:users:info': privData['view:users:info'] || isAdministrator, + // }); + // }; + + // privileges.admin.can = async function (privilege, uid) { + // const [isAdministrator, isUserAllowedTo] = await Promise.all([ + // user.isAdministrator(uid), + // helpers.isUserAllowedTo(privilege, uid, [0]), + // ]); + // return isAdministrator || isUserAllowedTo[0]; + // }; + + // privileges.admin.canGroup = async function (privilege, groupName) { + // return await groups.isMember(groupName, 'cid:0:privileges:groups:' + privilege); + // }; + + privileges.admin.give = async function (privileges, groupName) { + await helpers.giveOrRescind(groups.join, privileges, 'admin', groupName); + plugins.fireHook('action:privileges.admin.give', { + privileges: privileges, + groupNames: Array.isArray(groupName) ? groupName : [groupName], + }); + }; + + privileges.admin.rescind = async function (privileges, groupName) { + await helpers.giveOrRescind(groups.leave, privileges, 'admin', groupName); + plugins.fireHook('action:privileges.admin.rescind', { + privileges: privileges, + groupNames: Array.isArray(groupName) ? groupName : [groupName], + }); + }; + + // privileges.admin.userPrivileges = async function (uid) { + // const tasks = {}; + // privileges.admin.userPrivilegeList.forEach(function (privilege) { + // tasks[privilege] = groups.isMember(uid, 'cid:0:privileges:' + privilege); + // }); + // return await utils.promiseParallel(tasks); + // }; + + // privileges.admin.groupPrivileges = async function (groupName) { + // const tasks = {}; + // privileges.admin.groupPrivilegeList.forEach(function (privilege) { + // tasks[privilege] = groups.isMember(groupName, 'cid:0:privileges:' + privilege); + // }); + // return await utils.promiseParallel(tasks); + // }; +}; diff --git a/src/privileges/global.js b/src/privileges/global.js index 6738ff09c3..58f58746a5 100644 --- a/src/privileges/global.js +++ b/src/privileges/global.js @@ -101,18 +101,18 @@ module.exports = function (privileges) { privileges.global.give = async function (privileges, groupName) { await helpers.giveOrRescind(groups.join, privileges, 0, groupName); - plugins.fireHook('action:privileges.global.give', { - privileges: privileges, - groupNames: Array.isArray(groupName) ? groupName : [groupName], - }); + // plugins.fireHook('action:privileges.global.give', { + // privileges: privileges, + // groupNames: Array.isArray(groupName) ? groupName : [groupName], + // }); }; privileges.global.rescind = async function (privileges, groupName) { await helpers.giveOrRescind(groups.leave, privileges, 0, groupName); - plugins.fireHook('action:privileges.global.rescind', { - privileges: privileges, - groupNames: Array.isArray(groupName) ? groupName : [groupName], - }); + // plugins.fireHook('action:privileges.global.rescind', { + // privileges: privileges, + // groupNames: Array.isArray(groupName) ? groupName : [groupName], + // }); }; privileges.global.userPrivileges = async function (uid) { diff --git a/src/privileges/index.js b/src/privileges/index.js index 1a17f59241..b1cb6c8e76 100644 --- a/src/privileges/index.js +++ b/src/privileges/index.js @@ -43,6 +43,7 @@ privileges.groupPrivilegeList = privileges.userPrivilegeList.map(privilege => 'g privileges.privilegeList = privileges.userPrivilegeList.concat(privileges.groupPrivilegeList); require('./global')(privileges); +require('./admin')(privileges); require('./categories')(privileges); require('./topics')(privileges); require('./posts')(privileges); diff --git a/src/socket.io/admin/categories.js b/src/socket.io/admin/categories.js index c57eebc159..a9ecd1269f 100644 --- a/src/socket.io/admin/categories.js +++ b/src/socket.io/admin/categories.js @@ -61,9 +61,15 @@ Categories.setPrivilege = async function (socket, data) { throw new Error('[[error:no-user-or-group]]'); } - await privileges.categories[data.set ? 'give' : 'rescind']( - Array.isArray(data.privilege) ? data.privilege : [data.privilege], data.cid, data.member - ); + if (isNaN(parseInt(data.cid, 10))) { + await privileges[data.cid][data.set ? 'give' : 'rescind']( + Array.isArray(data.privilege) ? data.privilege : [data.privilege], data.member + ); + } else { + await privileges.categories[data.set ? 'give' : 'rescind']( + Array.isArray(data.privilege) ? data.privilege : [data.privilege], data.cid, data.member + ); + } await events.log({ uid: socket.uid, @@ -77,7 +83,9 @@ Categories.setPrivilege = async function (socket, data) { }; Categories.getPrivilegeSettings = async function (socket, cid) { - if (!parseInt(cid, 10)) { + if (cid === 'admin') { + return await privileges.admin.list(); + } else if (!parseInt(cid, 10)) { return await privileges.global.list(); } return await privileges.categories.list(cid); diff --git a/src/views/admin/manage/privileges.tpl b/src/views/admin/manage/privileges.tpl index 527dd86607..ce513ee2dc 100644 --- a/src/views/admin/manage/privileges.tpl +++ b/src/views/admin/manage/privileges.tpl @@ -11,11 +11,15 @@
- - - - - + {{{ if type.global }}} + + {{{ end }}} + {{{ if type.admin }}} + + {{{ end }}} + {{{ if type.cid }}} + + {{{ end }}}
diff --git a/src/views/admin/partials/global/privileges.tpl b/src/views/admin/partials/privileges/admin.tpl similarity index 100% rename from src/views/admin/partials/global/privileges.tpl rename to src/views/admin/partials/privileges/admin.tpl diff --git a/src/views/admin/partials/categories/privileges.tpl b/src/views/admin/partials/privileges/category.tpl similarity index 100% rename from src/views/admin/partials/categories/privileges.tpl rename to src/views/admin/partials/privileges/category.tpl diff --git a/src/views/admin/partials/privileges/global.tpl b/src/views/admin/partials/privileges/global.tpl new file mode 100644 index 0000000000..4b5973ef97 --- /dev/null +++ b/src/views/admin/partials/privileges/global.tpl @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + {function.spawnPrivilegeStates, privileges.groups.name, ../privileges} + + + + + + +
[[admin/manage/categories:privileges.section-group]]{privileges.labels.groups.name}
+ + + + {privileges.groups.name} +
+
+ +
+
+
+ [[admin/manage/categories:privileges.inherit]] +
+
+ + + + + + + + + + + + + + + + + + + + {function.spawnPrivilegeStates, privileges.users.username, ../privileges} + + + + + + + + + + + +
[[admin/manage/categories:privileges.section-user]]{privileges.labels.users.name}
+ + + +
{../icon:text}
+ +
{privileges.users.username}
+ +
+ [[admin/manage/privileges:global.no-users]] + +