Fixed FELIX-2254 User Admin Plugin
https://issues.apache.org/jira/browse/FELIX-2254
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1375745 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole-plugins/useradmin/src/main/resources/res/plugin.js b/webconsole-plugins/useradmin/src/main/resources/res/plugin.js
new file mode 100644
index 0000000..d474482
--- /dev/null
+++ b/webconsole-plugins/useradmin/src/main/resources/res/plugin.js
@@ -0,0 +1,372 @@
+/* your java script code here */
+
+var userTree = false;
+var selectedRole = false;
+var newDialogRole = false;
+var roleDetails = false;
+var roleDetailsHelp = false;
+var roleDetailsTable = false;
+var roleDetailsBody = false;
+var roleDetailsTemplate = false;
+var roleDetailsTemplateP = false;
+var roleDetailsTemplateC = false;
+
+function roleObj(node) {
+ node = node && node.attr ? node.attr('role') : false;
+ return node ? JSON.parse(node) : false;
+}
+
+var treeSettings = {
+ data : {
+ type : 'json',
+ opts : { 'static' : [] }
+ },
+ ui : { theme_name : 'themeroller' },
+ rules : { multiple : false, valid_children: ['root'] },
+ types : {
+ root : { valid_children: ['t0', 't1', 't2'] },
+ t2 : { valid_children: ['t0', 't1', 't2'] },
+ t1 : { valid_children: 'none' },
+ t0 : { valid_children: 'none' }
+ },
+ callback : {
+ onselect : function(node) {
+ var _role = $(node).attr('role');
+ if (_role) {
+ var role = JSON.parse( _role );
+ onSelectNode(role.name);
+ $(node).children('a').addClass('ui-priority-primary');
+ } else {
+ roleDetailsHelp.removeClass('ui-helper-hidden');
+ roleDetailsTable.addClass('ui-helper-hidden');
+ }
+ },
+ onparse : function (s, t) {
+ return $(s)
+ .find('li[rel=t2] > a > ins').addClass('ui-icon ui-icon-contact').end()
+ .find('li[rel=t1] > a > ins').addClass('ui-icon ui-icon-person').end()
+ .find('li[rel=t0] > a > ins').addClass('ui-icon ui-icon-bullet').end();
+ },
+ ondeselect : function(node) { $(node).children('a').removeClass('ui-priority-primary') },
+ ondblclk : function(node, tree_obj) {
+ var n = $(node);
+ var pp = tree_obj.parent(node);
+ var r = roleObj(n);
+ var g = roleObj(pp);
+ console.log(r, g);
+ if (r && g) {
+ if( isInMemberArray(r, g.members, 1) ) {
+ $.post(pluginRoot, { action: 'removeMember', role: r.name, group: g.name });
+ $.post(pluginRoot, { action: 'addRequiredMember', role: r.name, group: g.name }, function(data) {
+ pp.attr('role', JSON.stringify(data));
+ }, 'json');
+ n.addClass('required');
+ } else if( isInMemberArray(r, g.rmembers, 1) ) {
+ $.post(pluginRoot, { action: 'removeMember', role: r.name, group: g.name });
+ $.post(pluginRoot, { action: 'addMember', role: r.name, group: g.name }, function(data) {
+ pp.attr('role', JSON.stringify(data));
+ }, 'json');
+ n.removeClass('required');
+ }
+ }
+ },
+ beforemove : function(node, ref_node, type, tree_obj, is_copy) {
+ var _ = dragObj(node, ref_node, type, tree_obj);
+ // --- check if the move is valid:
+ // don't move things around the same/root level
+ if (_.to == false && _.from == false) return false;
+ // no copy to the root folder
+ if (is_copy && _.to == false) return false;
+ // no rearrange withing the folder
+ if (_.to != false && _.from != false && _.to.name == _.from.name) return false;
+ // already contains such a member
+ if (_.to != false && isMember(_.node, _.to)) return false;
+
+ // do copy-move
+ // unassign from the old group, if it is move
+ if (!is_copy && _.from) $.post(pluginRoot, {'action': 'removeMember', 'role' : _.node.name, 'group' : _.from.name} , function(data) {}, 'json');
+ // assign to the new group
+ if (_.to) $.post(pluginRoot, {'action': 'addMember', 'role' : _.node.name, 'group' : _.to.name} , function(data) {}, 'json');
+
+ return true;
+ }
+ }
+}
+
+$(function() {
+ userTree = $('#userTree');
+ roleDetails = $('#roleDetails');
+ roleDetailsTable = roleDetails.find('table');
+ roleDetailsHelp = roleDetails.find('#roleDetailsHelp');
+ roleDetailsBody = roleDetailsTable.find('tbody');
+ roleDetailsTemplateP = roleDetailsBody.find('tr:eq(0)');
+ roleDetailsTemplateC = roleDetailsBody.find('tr:eq(1)');
+ roleDetailsTemplate = roleDetailsBody.find('tr:eq(2)').clone();
+ roleDetailsBody.find('tr').not('.header').remove();
+
+ // add new property/credential code
+ $('tr.header span.ui-icon-plus').click(function() {
+ $(this).parent().parent().parent().parent().after(newProp());
+ });
+
+ // new role dialog
+ var _buttons = {};
+ _buttons[i18n.close] = function() {
+ $(this).dialog('close');
+ }
+ _buttons[i18n.add] = function() {
+ var _ = newDialogRole;
+ var n = _.find('input');
+ if (!n.val()) {
+ n.addClass('ui-state-error');
+ return false;
+ } else n.removeClass('ui-state-error');
+ var t = _.find('select').val();
+ $.post(pluginRoot, {'action': 'set', 'data' : JSON.stringify({'name': n.val(), 'type': new Number(t)})} , function(data) {
+ _.dialog('close');
+ $('#reload').click();
+ }, 'json');
+ }
+ newDialogRole = $("#newDialogRole").dialog({
+ autoOpen : false,
+ modal : true,
+ open : function() { $(this).find('input').val('').removeClass('ui-state-error') },
+ closeText: i18n.abort,
+ buttons : _buttons
+ });
+
+ // role info buttons
+ $('#delRole').click( function() {
+ if (selectedRole) $.post(pluginRoot, {'action': 'del', 'role' : selectedRole}, function() {
+ $('#reload').click();
+ });
+ });
+ $('#savRole').click( doSaveRole );
+
+ // top-frame buttons
+ $('#newRole').click( function() {
+ newDialogRole.dialog('open');
+ return false;
+ });
+ $('#reload').click( function() {
+ $.post(pluginRoot, {'action': 'list'} , function(data) {
+ roleDetailsHelp.removeClass('ui-helper-hidden');
+ roleDetailsTable.addClass('ui-helper-hidden');
+
+ var sortedGroups = sortGroups(data);
+ var treeRoot = buildTree(sortedGroups);
+
+ treeSettings.data.opts['static'] = treeRoot;
+ userTree.empty().tree(treeSettings);
+ }, 'json');
+ return false;
+ }).click();
+});
+
+function newProp() {
+ var tr = roleDetailsTemplate.clone()
+ .find('li').click( function() {
+ tr.remove();
+ }).end()
+ .find('select').change( function(evt) {
+ tr.find('.v').replaceWith('<input class="v" '+ ($(this).val().indexOf('password') == 0 ? 'type="password"' : '') + '/>');
+ initStaticWidgets(tr);
+ }).end()
+ initStaticWidgets(tr);
+ return tr;
+}
+function hashToArray(s) {
+ var r = [];
+ while(s.length > 0) {
+ r.push(parseInt(s.substring(0, 2), 16));
+ s = s.substring(2);
+ }
+ return r;
+}
+function strToArray(s) {
+ var r = [];
+ var el = s.split(',');
+ for(var i=0;i<el.length;i++) r.push( parseInt(el[i], 10) );
+ return r;
+}
+function doSaveRole() {
+ if (!selectedRole) return;
+ var doProps = true;
+ var data = {
+ name : selectedRole,
+ properties : {},
+ credentials : {}
+ };
+ roleDetailsBody.find('tr').each( function() {
+ var _ = $(this);
+ if (_.hasClass('header-props')) doProps = true;
+ else if (_.hasClass('header-cred')) doProps = false;
+ else {
+ var k = _.find('.k').val();
+ var v = _.find('.v').val();
+ var t = _.find('select').val();
+
+ if (t.indexOf('password-') == 0) {
+ var hash = CryptoJS[t.substring(9)](v).toString(CryptoJS.enc.Hex);
+ v = hashToArray(hash);
+ } else if (t == 'byte[]') {
+ v = strToArray(v);
+ }
+
+ if (doProps) data.properties[k] = v;
+ else data.credentials[k] = v;
+ }
+ });
+ $.post(pluginRoot, {'action': 'set', 'data' : JSON.stringify(data)});
+}
+
+function isInMemberArray(role, g) {
+ if(g) for(var i in g) if (g[i].name == role.name) return true;
+ return false;
+}
+
+function isMember(role, group) {
+ if (!role) return false;
+ if (!group) return false;
+ if (isInMemberArray(role, group.members)) return true;
+ if (isInMemberArray(role, group.rmembers)) return true;
+}
+
+function buildTree(sortedGroups) {
+ var treeRoot = {
+ data : i18n.root,
+ state: 'open',
+ attributes : { 'rel' : 'root' },
+ children: []
+ };
+ var treeNode = function(name, role, parent, req) {
+ if (!role) return;
+ if (!parent) parent = treeRoot.children;
+ var node = {
+ data : role.name,
+ attributes : {
+ 'rel' : 't' + role.type,
+ 'role' : JSON.stringify(role)
+ }
+ }
+ if (req) node.attributes['class'] = 'required';
+ parent.push(node);
+ if (role.type == 2) {
+ node['children'] = [];
+ node = node['children'];
+ if (role.members) $.each(role.members, function(idx, role) {
+ treeNode(role.name, role, node, 0);
+ });
+ if (role.rmembers) $.each(role.rmembers, function(idx, role) {
+ treeNode(role.name, role, node, 1);
+ });
+ }
+ }
+
+ $.each(sortedGroups, treeNode);
+ return treeRoot;
+}
+
+function sortGroups(data) {
+ var rootGroups = {}; // only root groups - without parents
+ var unassigned = {}; // non-groups, not assigned to any group
+ var processed = {}; // all processed entries
+ var u = 0;
+ var g = 0;
+ var r = 0;
+
+ var _st = function(map, n, role) {
+ if (typeof map[n] == 'undefined') { // not added - add
+ map[n] = role;
+ } else if (map[n] != false) { // already added
+ map[n] = false; // mark for removal
+ }
+ }
+
+ var groupF = function(i1, role) {
+ var n = role.name;
+ var t = role.type;
+
+ if (t == 2) { // group
+ // don't process twice
+ if (processed[n]) {
+ rootGroups[n] = false;
+ return true;
+ }
+ processed[n]=role;
+
+ _st(rootGroups, n, role);
+
+ if (role.members) $.each(role.members, groupF);
+ if (role.rmembers) $.each(role.rmembers, groupF);
+ g++;
+ } else { // role or user
+ if (t == 1) u++; else r++;
+ _st(unassigned, n, role);
+ }
+ }
+
+ $.each(data, groupF);
+ $('.statline').text( i18n.status.msgFormat(g,u,r) );
+
+ return $.extend(rootGroups, unassigned);
+}
+
+function onSelectNode(role) {
+ $.post(pluginRoot, {'action': 'get', 'role' : role} , function(data) {
+ selectedRole = role;
+ roleDetailsHelp.addClass('ui-helper-hidden');
+ roleDetailsTable.removeClass('ui-helper-hidden');
+ roleDetailsBody.find('tr').not('.header').remove();
+
+ var target = false;
+ var _append = function(k,v) {
+ var t = $.isArray(v) ? 'byte[]' : 'string';
+ target.after(newProp()
+ .data('k', k)
+ .find('input.k').val(k).end()
+ .find('input.v').val(v).end()
+ .find('select').val(t).end()
+ );
+ }
+ var x = data.properties;
+ if (x) {
+ target = roleDetailsTemplateP;
+ $.each(x, _append);
+ }
+ x = data.credentials;
+ if (x) {
+ target = roleDetailsTemplateC;
+ $.each(x, _append);
+ }
+ // show/user credentials view if user/or not (respectively)
+ x = roleDetailsBody.find('.header-cred');
+ if (data.type != 1) x.addClass('ui-helper-hidden');
+ else x.removeClass('ui-helper-hidden');
+ }, 'json')
+ return false;
+}
+
+function dragObj(node, ref_node, type, tree_obj) {
+ // determine the destination folder
+ var _role = false;
+ if ('inside' == type) {
+ _role = $(ref_node).attr('role');
+ } else {
+ _role = tree_obj.parent(ref_node)
+ _role = _role.attr ? _role.attr('role') : false;
+ }
+ var to = _role ? JSON.parse(_role) : false;
+ // determine object to move
+ _role = $(node).attr('role');
+ var source = JSON.parse(_role);
+ // determine the previous location (in case it is move, not copy)
+ _role = tree_obj.parent(node);
+ var from = _role.attr && _role.attr('role') ? JSON.parse(_role.attr('role')) : false;
+
+ return {
+ 'to' : to,
+ 'from' : from,
+ 'node' : source
+ }
+}