From 9b84a887d31374ea25fa2bc67de3d6e2a01ec516 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 25 Mar 2015 15:42:15 -0400 Subject: [PATCH] a huge frickin' number of changes for #2887. This is part of #2463 --- public/less/admin/admin.less | 11 ++ public/src/admin/manage/category.js | 72 ++++++++++- public/src/modules/autocomplete.js | 12 +- public/src/modules/helpers.js | 15 +++ src/controllers/admin.js | 9 +- src/groups.js | 16 ++- src/privileges/categories.js | 102 +++++++++++++++ src/socket.io/admin/categories.js | 116 +++++++----------- src/views/admin/manage/category.tpl | 55 +++++---- .../admin/partials/categories/permissions.tpl | 32 ----- 10 files changed, 305 insertions(+), 135 deletions(-) delete mode 100644 src/views/admin/partials/categories/permissions.tpl diff --git a/public/less/admin/admin.less b/public/less/admin/admin.less index 6331c3b1e2..0e35f3a6df 100644 --- a/public/less/admin/admin.less +++ b/public/less/admin/admin.less @@ -317,3 +317,14 @@ cursor: move; } } + +.privilege-table { + th { + font-size: 10px; + } + + img { + max-width: 24px; + max-height: 24px; + } +} diff --git a/public/src/admin/manage/category.js b/public/src/admin/manage/category.js index d6057e2663..c0344604e8 100644 --- a/public/src/admin/manage/category.js +++ b/public/src/admin/manage/category.js @@ -4,8 +4,9 @@ define('admin/manage/category', [ 'uploader', 'admin/modules/iconSelect', - 'admin/modules/colorpicker' -], function(uploader, iconSelect, colorpicker) { + 'admin/modules/colorpicker', + 'autocomplete' +], function(uploader, iconSelect, colorpicker, autocomplete) { var Category = {}; Category.init = function() { @@ -113,7 +114,7 @@ define('admin/manage/category', [ uploader.open(RELATIVE_PATH + '/api/admin/category/uploadpicture', { cid: cid }, 0, function(imageUrlOnServer) { inputEl.val(imageUrlOnServer); - var previewBox = inputEl.parent().siblings('.category-preview'); + var previewBox = inputEl.parent().parent().siblings('.category-preview'); previewBox.css('background', 'url(' + imageUrlOnServer + '?' + new Date().getTime() + ')') .css('background-size', 'cover'); modified(inputEl[0]); @@ -125,6 +126,8 @@ define('admin/manage/category', [ iconSelect.init($(this).find('i'), modified); }); + Category.setupPrivilegeTable(); + $(function() { @@ -312,5 +315,68 @@ define('admin/manage/category', [ // }); // }; + Category.setupPrivilegeTable = function() { + var searchEl = $('.privilege-search'), + searchObj = autocomplete.user(searchEl); + + // User search + addition to table + searchObj.on('autocompleteselect', function(ev, ui) { + socket.emit('admin.categories.setPrivilege', { + cid: ajaxify.variables.get('cid'), + privilege: 'read', + set: true, + member: ui.item.user.uid + }, function(err) { + if (err) { + return app.alertError(err.message); + } + + Category.refreshPrivilegeTable(); + searchEl.val(''); + }); + }); + + // Checkbox event capture + $('.privilege-table-container').on('change', 'input[type="checkbox"]', function() { + var checkboxEl = $(this), + privilege = checkboxEl.parent().attr('data-privilege'), + state = checkboxEl.prop('checked'), + rowEl = checkboxEl.parents('tr'), + member = rowEl.attr('data-group-slug') || rowEl.attr('data-uid'); + + if (member) { + socket.emit('admin.categories.setPrivilege', { + cid: ajaxify.variables.get('cid'), + privilege: privilege, + set: state, + member: member + }, function(err) { + if (err) { + return app.alertError(err.message); + } + + checkboxEl.replaceWith(''); + Category.refreshPrivilegeTable(); + }); + } else { + app.alertError('No member or group was selected'); + } + }) + }; + + Category.refreshPrivilegeTable = function() { + socket.emit('admin.categories.getPrivilegeSettings', 2, function(err, privileges) { + if (err) { + return app.alertError(err.message); + } + + templates.parse('admin/partials/categories/privileges', { + privileges: privileges + }, function(html) { + $('.privilege-table-container').html(html); + }); + }); + }; + return Category; }); \ No newline at end of file diff --git a/public/src/modules/autocomplete.js b/public/src/modules/autocomplete.js index d8b2311b98..55c15b8686 100644 --- a/public/src/modules/autocomplete.js +++ b/public/src/modules/autocomplete.js @@ -7,7 +7,7 @@ define('autocomplete', function() { var module = {}; module.user = function (input) { - input.autocomplete({ + return input.autocomplete({ delay: 100, source: function(request, response) { socket.emit('user.search', {query: request.term}, function(err, result) { @@ -17,7 +17,15 @@ define('autocomplete', function() { if (result && result.users) { var names = result.users.map(function(user) { - return user && user.username; + return user && { + label: user.username, + value: user.username, + user: { + uid: user.uid, + name: user.username, + slug: user.userslug + } + }; }); response(names); } diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js index 5361099476..dfecb7e78b 100644 --- a/public/src/modules/helpers.js +++ b/public/src/modules/helpers.js @@ -98,6 +98,21 @@ } }; + helpers.spawnPrivilegeStates = function(privileges) { + var states = []; + for(var priv in privileges) { + if (privileges.hasOwnProperty(priv)) { + states.push({ + name: priv, + state: privileges[priv] + }); + } + } + return states.map(function(priv) { + return ''; + }).join(''); + }; + exports.register = function() { var templates; diff --git a/src/controllers/admin.js b/src/controllers/admin.js index 77a1ff143b..6e58915038 100644 --- a/src/controllers/admin.js +++ b/src/controllers/admin.js @@ -6,6 +6,7 @@ var async = require('async'), user = require('../user'), categories = require('../categories'), + privileges = require('../privileges'), posts = require('../posts'), topics = require('../topics'), meta = require('../meta'), @@ -127,13 +128,17 @@ function getGlobalField(field, callback) { } adminController.categories.get = function(req, res, next) { - categories.getCategoryData(req.params.category_id, function(err, category) { + async.parallel({ + category: async.apply(categories.getCategoryData, req.params.category_id), + privileges: async.apply(privileges.categories.list, req.params.category_id) + }, function(err, data) { if (err) { return next(err); } res.render('admin/manage/category', { - category: category + category: data.category, + privileges: data.privileges }); }); }; diff --git a/src/groups.js b/src/groups.js index 43a376106f..a4369a6785 100644 --- a/src/groups.js +++ b/src/groups.js @@ -271,7 +271,15 @@ var async = require('async'), }; Groups.getGroupFields = function(groupName, fields, callback) { - db.getObjectFields('group:' + groupName, fields, callback); + Groups.getMultipleGroupFields([groupName], fields, function(err, groups) { + callback(err, groups ? groups[0] : null); + }); + }; + + Groups.getMultipleGroupFields = function(groups, fields, callback) { + db.getObjectsFields(groups.map(function(group) { + return 'group:' + group; + }), fields, callback); }; Groups.setGroupField = function(groupName, field, value, callback) { @@ -306,6 +314,12 @@ var async = require('async'), db.getSortedSetRevRange('group:' + groupName + ':members', start, end, callback); }; + Groups.getMembersOfGroups = function(groupNames, callback) { + db.getSortedSetsMembers(groupNames.map(function(name) { + return 'group:' + name + ':members'; + }), callback); + }; + Groups.isMember = function(uid, groupName, callback) { if (!uid || parseInt(uid, 10) <= 0) { return callback(null, false); diff --git a/src/privileges/categories.js b/src/privileges/categories.js index d2f4938a7b..92cf9b2a56 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -13,6 +13,108 @@ module.exports = function(privileges) { privileges.categories = {}; + privileges.categories.list = function(cid, callback) { + // Method used in admin/category controller to show all users with privs in that given cid + async.parallel({ + labels: function(next) { + async.parallel({ + users: async.apply(plugins.fireHook, 'filter:privileges.list_human', + ['Find category', 'Access & Read', 'Create Topics', 'Reply to Topics', 'Moderator'].map(function(name) { + return { + name: name + }; + }) + ), + groups: async.apply(plugins.fireHook, 'filter:privileges.groups.list_human', + ['Find category', 'Access & Read', 'Create Topics', 'Reply to Topics'].map(function(name) { + return { + name: name + }; + }) + ) + }, next); + }, + users: function(next) { + var privileges; + async.waterfall([ + async.apply(plugins.fireHook, 'filter:privileges.list', [ + 'find', 'read', 'topics:create', 'topics:reply', 'mods' + ]), + function(privs, next) { + privileges = privs; + groups.getMembersOfGroups(privs.map(function(privilege) { + return 'cid:' + cid + ':privileges:' + privilege; + }), next); + }, + function(memberSets, next) { + // Reduce into a single array + var members = memberSets.reduce(function(combined, curMembers) { + return combined.concat(curMembers); + }).filter(function(member, index, combined) { + return combined.indexOf(member) === index; + }); + + user.getMultipleUserFields(members, ['picture', 'username'], function(err, memberData) { + memberData = memberData.map(function(member) { + member.privileges = {}; + for(var x=0,numPrivs=privileges.length;x
-
Categories
+
Category Settings
-
-
- -
-
-

{category.name}

{category.description}

@@ -68,7 +55,7 @@
- +
@@ -81,6 +68,24 @@
+ +
+
Privileges / Access Control
+
+

+ You can configure the access control privileges for this category in this section. Privileges can be granted on a per-user or + a per-group basis. You can add a new user or group to this table by searching for them in the form below. +

+

+ Note: Privilege settings take effect immediately. It is not necessary to save the category after adjusting + these settings. +

+
+ +
+ +
+
@@ -99,11 +104,11 @@
- +
- +
@@ -113,12 +118,16 @@
Categories Control Panel
-
- - +
+
+ +
+
+ +

- +
@@ -133,4 +142,6 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/src/views/admin/partials/categories/permissions.tpl b/src/views/admin/partials/categories/permissions.tpl deleted file mode 100644 index a8077e2aa4..0000000000 --- a/src/views/admin/partials/categories/permissions.tpl +++ /dev/null @@ -1,32 +0,0 @@ - \ No newline at end of file