mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-05-07 13:57:24 +02:00
feat: acp privileges (WIP)
This commit is contained in:
@@ -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"
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]]');
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
107
src/privileges/admin.js
Normal file
107
src/privileges/admin.js
Normal file
@@ -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);
|
||||
// };
|
||||
};
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -11,11 +11,15 @@
|
||||
</div>
|
||||
|
||||
<div class="privilege-table-container">
|
||||
<!-- IF cid -->
|
||||
<!-- IMPORT admin/partials/categories/privileges.tpl -->
|
||||
<!-- ELSE -->
|
||||
<!-- IMPORT admin/partials/global/privileges.tpl -->
|
||||
<!-- ENDIF cid -->
|
||||
{{{ if type.global }}}
|
||||
<!-- IMPORT admin/partials/privileges/global.tpl -->
|
||||
{{{ end }}}
|
||||
{{{ if type.admin }}}
|
||||
<!-- IMPORT admin/partials/privileges/admin.tpl -->
|
||||
{{{ end }}}
|
||||
{{{ if type.cid }}}
|
||||
<!-- IMPORT admin/partials/privileges/category.tpl -->
|
||||
{{{ end }}}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
86
src/views/admin/partials/privileges/global.tpl
Normal file
86
src/views/admin/partials/privileges/global.tpl
Normal file
@@ -0,0 +1,86 @@
|
||||
<label>[[admin/manage/privileges:group-privileges]]</label>
|
||||
<table class="table table-striped privilege-table">
|
||||
<thead>
|
||||
<tr><!-- zebrastripe reset --></tr>
|
||||
<tr>
|
||||
<th colspan="2">[[admin/manage/categories:privileges.section-group]]</th>
|
||||
<!-- BEGIN privileges.labels.groups -->
|
||||
<th class="text-center">{privileges.labels.groups.name}</th>
|
||||
<!-- END privileges.labels.groups -->
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- BEGIN privileges.groups -->
|
||||
<tr data-group-name="{privileges.groups.nameEscaped}" data-private="<!-- IF privileges.groups.isPrivate -->1<!-- ELSE -->0<!-- ENDIF privileges.groups.isPrivate -->">
|
||||
<td>
|
||||
<!-- IF privileges.groups.isPrivate -->
|
||||
<i class="fa fa-lock text-muted" title="[[admin/manage/categories:privileges.group-private]]"></i>
|
||||
<!-- ENDIF privileges.groups.isPrivate -->
|
||||
{privileges.groups.name}
|
||||
</td>
|
||||
<td></td>
|
||||
{function.spawnPrivilegeStates, privileges.groups.name, ../privileges}
|
||||
</tr>
|
||||
<!-- END privileges.groups -->
|
||||
<tr>
|
||||
<td colspan="{privileges.columnCount}">
|
||||
<div class="btn-toolbar">
|
||||
<button type="button" class="btn btn-primary pull-right" data-ajaxify="false" data-action="search.group">
|
||||
[[admin/manage/categories:privileges.search-group]]
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="help-block">
|
||||
[[admin/manage/categories:privileges.inherit]]
|
||||
</div>
|
||||
<hr/>
|
||||
<label>[[admin/manage/privileges:user-privileges]]</label>
|
||||
<table class="table table-striped privilege-table">
|
||||
<thead>
|
||||
<tr class="privilege-table-header">
|
||||
<th colspan="15"></th>
|
||||
</tr><tr><!-- zebrastripe reset --></tr>
|
||||
<tr>
|
||||
<th colspan="2">[[admin/manage/categories:privileges.section-user]]</th>
|
||||
<!-- BEGIN privileges.labels.users -->
|
||||
<th class="text-center">{privileges.labels.users.name}</th>
|
||||
<!-- END privileges.labels.users -->
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- IF privileges.users.length -->
|
||||
<!-- BEGIN privileges.users -->
|
||||
<tr data-uid="{privileges.users.uid}">
|
||||
<td>
|
||||
<!-- IF ../picture -->
|
||||
<img class="avatar avatar-sm" src="{privileges.users.picture}" title="{privileges.users.username}" />
|
||||
<!-- ELSE -->
|
||||
<div class="avatar avatar-sm" style="background-color: {../icon:bgColor};">{../icon:text}</div>
|
||||
<!-- ENDIF ../picture -->
|
||||
</td>
|
||||
<td>{privileges.users.username}</td>
|
||||
{function.spawnPrivilegeStates, privileges.users.username, ../privileges}
|
||||
</tr>
|
||||
<!-- END privileges.users -->
|
||||
<tr>
|
||||
<td colspan="{privileges.columnCount}">
|
||||
<button type="button" class="btn btn-primary pull-right" data-ajaxify="false" data-action="search.user">
|
||||
[[admin/manage/categories:privileges.search-user]]
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- ELSE -->
|
||||
<tr>
|
||||
<td colspan="{privileges.columnCount}">
|
||||
[[admin/manage/privileges:global.no-users]]
|
||||
<button type="button" class="btn btn-primary pull-right" data-ajaxify="false" data-action="search.user">
|
||||
[[admin/manage/categories:privileges.search-user]]
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- ENDIF privileges.users.length -->
|
||||
</tbody>
|
||||
</table>
|
||||
Reference in New Issue
Block a user