chat privilege
parent
094bab24c9
commit
4a73621dca
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"global": "Global",
|
||||||
|
"global.description": "You can configure the global privileges in this section. Privileges can be granted on a per-user or a per-group basis. You can add a new user to this table by searching for them in the form below.",
|
||||||
|
"global.warning": "<strong>Note</strong>: Privilege settings take effect immediately. It is not necessary to save after adjusting these settings.",
|
||||||
|
"global.no-users": "No user-specific global privileges."
|
||||||
|
}
|
@ -0,0 +1,158 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
|
define('admin/manage/privileges', [
|
||||||
|
'autocomplete',
|
||||||
|
'translator',
|
||||||
|
'benchpress',
|
||||||
|
], function (autocomplete, translator, Benchpress) {
|
||||||
|
var Privileges = {};
|
||||||
|
|
||||||
|
Privileges.init = function () {
|
||||||
|
$('#category-selector').on('change', function () {
|
||||||
|
var val = $(this).val();
|
||||||
|
if (val !== 'global') {
|
||||||
|
ajaxify.go('admin/manage/categories/' + $(this).val() + '#privileges');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Privileges.setupPrivilegeTable();
|
||||||
|
};
|
||||||
|
|
||||||
|
Privileges.setupPrivilegeTable = function () {
|
||||||
|
$('.privilege-table-container').on('change', 'input[type="checkbox"]', function () {
|
||||||
|
var checkboxEl = $(this);
|
||||||
|
var privilege = checkboxEl.parent().attr('data-privilege');
|
||||||
|
var state = checkboxEl.prop('checked');
|
||||||
|
var rowEl = checkboxEl.parents('tr');
|
||||||
|
var member = rowEl.attr('data-group-name') || rowEl.attr('data-uid');
|
||||||
|
var isPrivate = parseInt(rowEl.attr('data-private') || 0, 10);
|
||||||
|
var isGroup = rowEl.attr('data-group-name') !== undefined;
|
||||||
|
|
||||||
|
if (member) {
|
||||||
|
Privileges.setPrivilege(member, privilege, state, checkboxEl);
|
||||||
|
} else {
|
||||||
|
app.alertError('[[error:invalid-data]]');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.privilege-table-container').on('click', '[data-action="search.user"]', Privileges.addUserToPrivilegeTable);
|
||||||
|
$('.privilege-table-container').on('click', '[data-action="search.group"]', Privileges.addGroupToPrivilegeTable);
|
||||||
|
|
||||||
|
Privileges.exposeAssumedPrivileges();
|
||||||
|
};
|
||||||
|
|
||||||
|
Privileges.refreshPrivilegeTable = function () {
|
||||||
|
socket.emit('admin.categories.getPrivilegeSettings', function (err, privileges) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
Benchpress.parse('admin/partials/global/privileges', {
|
||||||
|
privileges: privileges,
|
||||||
|
}, function (html) {
|
||||||
|
translator.translate(html, function (html) {
|
||||||
|
$('.privilege-table-container').html(html);
|
||||||
|
Privileges.exposeAssumedPrivileges();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Privileges.exposeAssumedPrivileges = function () {
|
||||||
|
/*
|
||||||
|
If registered-users has a privilege enabled, then all users and groups of that privilege
|
||||||
|
should be assumed to have that privilege as well, even if not set in the db, so reflect
|
||||||
|
this arrangement in the table
|
||||||
|
*/
|
||||||
|
var privs = [];
|
||||||
|
$('.privilege-table tr[data-group-name="registered-users"] td input[type="checkbox"]').parent().each(function (idx, el) {
|
||||||
|
if ($(el).find('input').prop('checked')) {
|
||||||
|
privs.push(el.getAttribute('data-privilege'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (var x = 0, numPrivs = privs.length; x < numPrivs; x += 1) {
|
||||||
|
var inputs = $('.privilege-table tr[data-group-name]:not([data-group-name="registered-users"],[data-group-name="guests"]) td[data-privilege="' + privs[x] + '"] input');
|
||||||
|
inputs.each(function (idx, el) {
|
||||||
|
if (!el.checked) {
|
||||||
|
el.indeterminate = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Privileges.setPrivilege = function (member, privilege, state, checkboxEl) {
|
||||||
|
socket.emit('admin.categories.setPrivilege', {
|
||||||
|
cid: 0,
|
||||||
|
privilege: privilege,
|
||||||
|
set: state,
|
||||||
|
member: member,
|
||||||
|
}, function (err) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
checkboxEl.replaceWith('<i class="fa fa-spin fa-spinner"></i>');
|
||||||
|
Privileges.refreshPrivilegeTable();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Privileges.addUserToPrivilegeTable = function () {
|
||||||
|
var modal = bootbox.dialog({
|
||||||
|
title: '[[admin/manage/categories:alert.find-user]]',
|
||||||
|
message: '<input class="form-control input-lg" placeholder="[[admin/manage/categories:alert.user-search]]" />',
|
||||||
|
show: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
modal.on('shown.bs.modal', function () {
|
||||||
|
var inputEl = modal.find('input');
|
||||||
|
|
||||||
|
autocomplete.user(inputEl, function (ev, ui) {
|
||||||
|
socket.emit('admin.categories.setPrivilege', {
|
||||||
|
cid: 0,
|
||||||
|
privilege: ['chat'],
|
||||||
|
set: true,
|
||||||
|
member: ui.item.user.uid,
|
||||||
|
}, function (err) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
Privileges.refreshPrivilegeTable();
|
||||||
|
modal.modal('hide');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Privileges.addGroupToPrivilegeTable = function () {
|
||||||
|
var modal = bootbox.dialog({
|
||||||
|
title: '[[admin/manage/categories:alert.find-group]]',
|
||||||
|
message: '<input class="form-control input-lg" placeholder="[[admin/manage/categories:alert.group-search]]" />',
|
||||||
|
show: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
modal.on('shown.bs.modal', function () {
|
||||||
|
var inputEl = modal.find('input');
|
||||||
|
|
||||||
|
autocomplete.group(inputEl, function (ev, ui) {
|
||||||
|
socket.emit('admin.categories.setPrivilege', {
|
||||||
|
cid: 0,
|
||||||
|
privilege: ['groups:chat'],
|
||||||
|
set: true,
|
||||||
|
member: ui.item.group.name,
|
||||||
|
}, function (err) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
Privileges.refreshPrivilegeTable();
|
||||||
|
modal.modal('hide');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return Privileges;
|
||||||
|
});
|
@ -0,0 +1,25 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
|
|
||||||
|
var categories = require('../../categories');
|
||||||
|
var privileges = require('../../privileges');
|
||||||
|
|
||||||
|
var privilegesController = module.exports;
|
||||||
|
|
||||||
|
privilegesController.get = function (req, res, callback) {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
async.parallel({
|
||||||
|
privileges: async.apply(privileges.global.list),
|
||||||
|
allCategories: async.apply(categories.buildForSelect, req.uid, 'read'),
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
function (data) {
|
||||||
|
res.render('admin/manage/privileges', {
|
||||||
|
privileges: data.privileges,
|
||||||
|
allCategories: data.allCategories,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
|
};
|
@ -0,0 +1,171 @@
|
|||||||
|
|
||||||
|
'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');
|
||||||
|
|
||||||
|
module.exports = function (privileges) {
|
||||||
|
privileges.global = {};
|
||||||
|
|
||||||
|
privileges.global.privilegeLabels = [
|
||||||
|
{ name: 'Chat' },
|
||||||
|
];
|
||||||
|
|
||||||
|
privileges.global.userPrivilegeList = [
|
||||||
|
'chat',
|
||||||
|
];
|
||||||
|
|
||||||
|
privileges.global.groupPrivilegeList = privileges.global.userPrivilegeList.map(function (privilege) {
|
||||||
|
return 'groups:' + privilege;
|
||||||
|
});
|
||||||
|
|
||||||
|
privileges.global.list = function (callback) {
|
||||||
|
var privilegeLabels = privileges.global.privilegeLabels.slice();
|
||||||
|
var userPrivilegeList = privileges.global.userPrivilegeList.slice();
|
||||||
|
var groupPrivilegeList = privileges.global.groupPrivilegeList.slice();
|
||||||
|
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
async.parallel({
|
||||||
|
labels: function (next) {
|
||||||
|
async.parallel({
|
||||||
|
users: async.apply(plugins.fireHook, 'filter:privileges.global.list_human', privilegeLabels),
|
||||||
|
groups: async.apply(plugins.fireHook, 'filter:privileges.global.groups.list_human', privilegeLabels),
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
users: function (next) {
|
||||||
|
var userPrivileges;
|
||||||
|
var memberSets;
|
||||||
|
async.waterfall([
|
||||||
|
async.apply(plugins.fireHook, 'filter:privileges.global.list', userPrivilegeList),
|
||||||
|
function (_privs, next) {
|
||||||
|
userPrivileges = _privs;
|
||||||
|
groups.getMembersOfGroups(userPrivileges.map(function (privilege) {
|
||||||
|
return 'cid:0:privileges:' + privilege;
|
||||||
|
}), next);
|
||||||
|
},
|
||||||
|
function (_memberSets, next) {
|
||||||
|
memberSets = _memberSets.map(function (set) {
|
||||||
|
return set.map(function (uid) {
|
||||||
|
return parseInt(uid, 10);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var members = _.uniq(_.flatten(memberSets));
|
||||||
|
|
||||||
|
user.getUsersFields(members, ['picture', 'username'], next);
|
||||||
|
},
|
||||||
|
function (memberData, next) {
|
||||||
|
memberData.forEach(function (member) {
|
||||||
|
member.privileges = {};
|
||||||
|
for (var x = 0, numPrivs = userPrivileges.length; x < numPrivs; x += 1) {
|
||||||
|
member.privileges[userPrivileges[x]] = memberSets[x].indexOf(parseInt(member.uid, 10)) !== -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
next(null, memberData);
|
||||||
|
},
|
||||||
|
], next);
|
||||||
|
},
|
||||||
|
groups: function (next) {
|
||||||
|
var groupPrivileges;
|
||||||
|
async.waterfall([
|
||||||
|
async.apply(plugins.fireHook, 'filter:privileges.global.groups.list', groupPrivilegeList),
|
||||||
|
function (_privs, next) {
|
||||||
|
groupPrivileges = _privs;
|
||||||
|
async.parallel({
|
||||||
|
memberSets: function (next) {
|
||||||
|
groups.getMembersOfGroups(groupPrivileges.map(function (privilege) {
|
||||||
|
return 'cid:0:privileges:' + privilege;
|
||||||
|
}), next);
|
||||||
|
},
|
||||||
|
groupNames: function (next) {
|
||||||
|
groups.getGroups('groups:createtime', 0, -1, next);
|
||||||
|
},
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
function (results, next) {
|
||||||
|
var memberSets = results.memberSets;
|
||||||
|
var uniqueGroups = _.uniq(_.flatten(memberSets));
|
||||||
|
|
||||||
|
var groupNames = results.groupNames.filter(function (groupName) {
|
||||||
|
return groupName.indexOf(':privileges:') === -1 && uniqueGroups.indexOf(groupName) !== -1;
|
||||||
|
});
|
||||||
|
|
||||||
|
var registeredUsersIndex = groupNames.indexOf('registered-users');
|
||||||
|
if (registeredUsersIndex !== -1) {
|
||||||
|
groupNames.splice(0, 0, groupNames.splice(registeredUsersIndex, 1)[0]);
|
||||||
|
} else {
|
||||||
|
groupNames = ['registered-users'].concat(groupNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
var adminIndex = groupNames.indexOf('administrators');
|
||||||
|
if (adminIndex !== -1) {
|
||||||
|
groupNames.splice(adminIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var memberPrivs;
|
||||||
|
|
||||||
|
var memberData = groupNames.map(function (member) {
|
||||||
|
memberPrivs = {};
|
||||||
|
|
||||||
|
for (var x = 0, numPrivs = groupPrivileges.length; x < numPrivs; x += 1) {
|
||||||
|
memberPrivs[groupPrivileges[x]] = memberSets[x].indexOf(member) !== -1;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: member,
|
||||||
|
privileges: memberPrivs,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
next(null, memberData);
|
||||||
|
},
|
||||||
|
function (memberData, next) {
|
||||||
|
// Grab privacy info for the groups as well
|
||||||
|
async.map(memberData, function (member, next) {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
groups.isPrivate(member.name, next);
|
||||||
|
},
|
||||||
|
function (isPrivate, next) {
|
||||||
|
member.isPrivate = isPrivate;
|
||||||
|
next(null, member);
|
||||||
|
},
|
||||||
|
], next);
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
], next);
|
||||||
|
},
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
function (payload, next) {
|
||||||
|
// 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;
|
||||||
|
next(null, payload);
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
privileges.global.can = function (privilege, uid, callback) {
|
||||||
|
helpers.some([
|
||||||
|
function (next) {
|
||||||
|
helpers.isUserAllowedTo(privilege, uid, [0], function (err, results) {
|
||||||
|
next(err, Array.isArray(results) && results.length ? results[0] : false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
user.isGlobalModerator(uid, next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
user.isAdministrator(uid, next);
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
@ -0,0 +1,12 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
|
var groups = require('../../groups');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'Give chat privilege to registered-users',
|
||||||
|
timestamp: Date.UTC(2017, 11, 18),
|
||||||
|
method: function (callback) {
|
||||||
|
groups.join('cid:0:privileges:group:chat', 'registered-users', callback);
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,34 @@
|
|||||||
|
<div class="row">
|
||||||
|
<form role="form" class="category">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3 pull-right">
|
||||||
|
<select id="category-selector" class="form-control">
|
||||||
|
<option value="global" selected>[[admin/manage/privileges:global]]</option>
|
||||||
|
<option disabled>_____________</option>
|
||||||
|
<!-- BEGIN allCategories -->
|
||||||
|
<option value="{allCategories.value}">{allCategories.text}</option>
|
||||||
|
<!-- END allCategories -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<div class="">
|
||||||
|
<p>
|
||||||
|
[[admin/manage/privileges:global.description]]
|
||||||
|
</p>
|
||||||
|
<p class="text-warning">
|
||||||
|
[[admin/manage/privileges:global.warning]]
|
||||||
|
</p>
|
||||||
|
<hr />
|
||||||
|
<div class="privilege-table-container">
|
||||||
|
<!-- IMPORT admin/partials/global/privileges.tpl -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="save" class="floating-button mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect mdl-button--colored">
|
||||||
|
<i class="material-icons">save</i>
|
||||||
|
</button>
|
@ -0,0 +1,86 @@
|
|||||||
|
<table class="table table-striped privilege-table">
|
||||||
|
<thead>
|
||||||
|
<tr class="privilege-table-header">
|
||||||
|
<th colspan="3"></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>
|
||||||
|
|
||||||
|
<table class="table table-striped privilege-table">
|
||||||
|
<thead>
|
||||||
|
<tr class="privilege-table-header">
|
||||||
|
<th colspan="3"></th>
|
||||||
|
</tr><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.name}" 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>
|
Loading…
Reference in New Issue