[enh] Add/remove users and permissions into groups

This commit is contained in:
ljf 2019-10-17 02:32:57 +02:00
parent 73abafb2c4
commit 6fe0044adb
8 changed files with 245 additions and 117 deletions

View file

@ -665,15 +665,35 @@ input[type='radio'].nice-radio {
/** Permissions View **/
#view-permissions {
.panel-heading a {
text-decoration: none;
&.group-delete {
float:right;
color:lighten(@label-danger-bg, 20%);
:hover {
color:@label-danger-bg;
}
}
}
.panel-body {
h3 {
margin-top:0;
}
button.dropdown-toggle {
line-height: 15.666px;
top: -1.666px;
}
.dropdown-menu {
max-height: 200px;
overflow-y: scroll;
}
.label-removable {
display:inline-block;
font-size:1.3em;
color:#666;
background-color:#ccc;
background-color:#eee;
border: #ddd 1px solid;
font-weight: normal;
margin-right:7px;
margin-bottom:7px;
.label-separator {
@ -681,11 +701,11 @@ input[type='radio'].nice-radio {
color:white;
}
> a {
color:white;
color:lighten(@label-danger-bg, 20%);
text-decoration: none;
}
> a:hover {
color:@label-danger-bg;
color:@label-danger-bg;
}
}
}

View file

@ -10,31 +10,100 @@
*
*/
// List groups and permissions
function updateGroup(model, params) {
var type = params.type;
var operation = params.operation;
var item = params.item;
var groupname = params.group;
var group = data.groups[groupname];
var to = (operation == 'add')?group[type]:group[type + 'Inv'];
var from = (operation == 'add')?group[type+'Inv']:group[type];
// Do nothing, if array of destination already contains the item
if (from.indexOf(item) === -1) return;
// Hack to disable pacman loader if any
if ($('div.loader').length === 0) {
$('#main').append('<div class="loader loader-content" style="display: none"></div>');
}
$('div.loader').css('display', 'none');
// Update group
var params = {}; var url;
if (type == 'members') {
url = '/users/groups/' + groupname;
params[operation] = [item];
}
else {
url = '/users/permissions/' + item;
params[operation] = [groupname];
}
c.api(url, function(data_update) {
to.push(item);
from.splice(from.indexOf(item), 1);
updateView(data);
}, 'PUT', params);
}
function updateView(model) {
for (var group in model.groups) {
model.groups[group].permissions.sort();
model.groups[group].permissionsInv.sort();
model.groups[group].members.sort();
model.groups[group].membersInv.sort();
}
c.view('user/user_permission', model, function () {
jQuery(".group-update").on('click', function (e) {
updateGroup(model, jQuery(this)[0].dataset);
return false;
});
jQuery(".group-add-user").on('click', function (e) {
data.groups[$(this)[0].dataset.user].display = true;
updateView(data);
return false;
});
});
}
this.displayPermission = // List groups and permissions
app.get('#/permissions', function (c) {
c.api('/users/groups?full&include_primary_groups', function(data_groups) {
c.api('/users', function(data_users) {
//var perms = data_permissions.permissions;
var specific_perms = {};
var all_perms = [];
for (var user in data_users.users) {
console.log(user);
if (user in data_groups.groups) {
if (data_groups.groups[user].permissions.length > 0)
specific_perms[user] = data_groups.groups[user];
delete data_groups.groups[user];
}
}
data_groups.groups['all_users'].special = true;
data_groups.groups['visitors'].special = true;
data = {
'groups':data_groups.groups,
'users_with_specific_permissions': specific_perms,
'users': Object.keys(data_users.users),
'permissions': all_perms
};
c.view('user/user_permission', data);
c.api('/users/permissions?short', function(data_permissions) {
//var perms = data_permissions.permissions;
var specific_perms = {};
var all_perms = data_permissions.permissions;
var users = Object.keys(data_users.users);
for (var group in data_groups.groups) {
data_groups.groups[group].primary = users.indexOf(group) !== -1;
data_groups.groups[group].permissionsInv = all_perms.filter(function(item) {
return data_groups.groups[group].permissions.indexOf(item) === -1;
});
data_groups.groups[group].membersInv = users.filter(function(item) {
return data_groups.groups[group].members.indexOf(item) === -1;
});
}
Handlebars.registerHelper('call', function () {
var args = Array.prototype.slice.call(arguments);
var func = args.shift();
args.pop();
return func.apply(null, args);
});
data_groups.groups['all_users'].special = true;
data_groups.groups['visitors'].special = true;
data = {
'groups':data_groups.groups,
'displayPermission': function (text) {
text = text.replace('.main', '');
if (text.indexOf('.') > -1)
text = text.replace('.', ' (') + ')';
return text;
},
'displayUser': function (text) {
return text;
},
};
updateView(data);
});
});
});
});
@ -54,6 +123,30 @@
c.redirect('#/permissions');
}, 'POST', c.params.toHash());
});
app.get('#/groups/:group/delete', function (c) {
var params = {};
// make confirm content
var confirmModalContent = $('<div>'+ y18n.t('confirm_delete', [c.params['group']]) +'</div>');
// display confirm modal
c.confirm(
y18n.t('groups'),
confirmModalContent,
function(){
c.api('/users/groups/'+ c.params['group'], function(data) {
c.redirect('#/permissions');
}, 'DELETE', params);
},
function(){
//store.clear('slide');
c.redirect('#/permissions');
}
);
});
/**
* Users

View file

@ -276,7 +276,7 @@
callback();
// Force scrollTop on page load
$('html, body').scrollTop(0);
//$('html, body').scrollTop(0);
});
};

View file

@ -101,12 +101,35 @@
// equality stuff because mustache/Handlebars is lame
// source https://stackoverflow.com/a/31632215
Handlebars.registerHelper('eq', function(a, b) {
return a === b;
});
Handlebars.registerHelper('neq', function(a, b) {
return a !== b;
Handlebars.registerHelper({
eq: function(a, b) {
return a === b;
},
neq: function(a, b) {
return a !== b;
},
lt: function (v1, v2) {
return v1 < v2;
},
gt: function (v1, v2) {
return v1 > v2;
},
lte: function (v1, v2) {
return v1 <= v2;
},
gte: function (v1, v2) {
return v1 >= v2;
},
and: function () {
return Array.prototype.slice.call(arguments).every(function (arg) {
return (Array.isArray(arg))?arg.length !== 0:arg;
});
},
or: function () {
return Array.prototype.slice.call(arguments, 0, -1).some(function (arg) {
return (Array.isArray(arg))?arg.length !== 0:arg;
});
}
});
Handlebars.registerHelper('in', function(a) {

View file

@ -160,7 +160,18 @@
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
"group": "Group",
"group_name": "Group name",
"group_all_users": "All users",
"group_visitors": "Visitors",
"group_format_name_help": "You can use alpha-numeric chars and space",
"group_add_member": "Add a user",
"group_add_permission": "Add a permission",
"group_new": "New group",
"group_manage_permissions": "Manage permissions and groups",
"group_all_users_group_explanation": "This is a specific group containing all users registered on this instance",
"group_visitors_group_explanation": "it is a specific group that represents visitors who do not have an account on your yunohost instance",
"group_specific_permissions": "User specific permissions",
"group_permissions": "Groups and permissions",
"permissions": "Permissions",
"home": "Home",
"hook_adminjs_group_configuration": "System configurations",
"hook_conf_cron": "Automatic tasks",
@ -274,13 +285,6 @@
"logs_share_with_yunopaste": "Share with YunoPaste",
"logs_more": "Display more lines",
"path_url": "Path",
"perm_add_user": "Add a user",
"perm_add_permission": "Add a permission",
"perm_groups_new": "New group",
"perm_manage_permissions": "Manage permissions",
"perm_all_users_group_explanation": "This is a specific group containing all users registered on this instance",
"perm_specific_permissions": "User specific permissions",
"permissions": "Permissions",
"port": "Port",
"ports": "Ports",
"postinstall": "Post-installation",

View file

@ -3,8 +3,8 @@
<a href="#/users" class="visible-xs">&hellip;</a>
<a href="#/users" class="hidden-xs">{{t 'users'}}</a>
<a href="#/permissions" class="visible-xs">&hellip;</a>
<a href="#/permissions" class="hidden-xs">{{t 'permissions'}}</a>
<a href="#/groups/create">{{t 'perm_groups_new'}}</a>
<a href="#/permissions" class="hidden-xs">{{t 'group_permissions'}}</a>
<a href="#/groups/create">{{t 'group_new'}}</a>
</div>
<div class="separator"></div>

View file

@ -5,7 +5,7 @@
<div class="actions-group">
<a href="#/permissions" class="btn btn-info">
<span class="fa-key-modern"></span> {{t 'perm_manage_permissions'}}
<span class="fa-key-modern"></span> {{t 'group_manage_permissions'}}
</a>
<a role="button" href="#/users/create" class="btn btn-success slide">
<span class="fa-plus"></span> {{t 'users_new'}}

View file

@ -1,138 +1,126 @@
<div class="btn-breadcrumb">
<a href="#/"><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
<a href="#/users">{{t 'users'}}</a>
<a href="#/permissions">{{t 'perm_manage_permissions'}}</a>
<a href="#/permissions">{{t 'group_permissions'}}</a>
</div>
<div class="actions-group">
<a role="button" href="#/groups/create" class="btn btn-success slide">
<span class="fa-plus"></span> {{t 'perm_groups_new'}}
<span class="fa-plus"></span> {{t 'group_new'}}
</a>
</div>
<div class="separator"></div>
{{#*inline "label"}}
<span class="label label-default label-removable">
<span class="fa-fw fa-{{icon}}"></span>
{{text}}
<span class="label-separator" aria-hidden="true">|</span>
<a role="button" data-type="{{type}}s" data-operation="remove" data-item="{{value}}" data-group="{{group}}" class="group-update">
<span class="fa-close" style="margin-left:5px"></span>
<span class="sr-only">{{t 'delete'}}</span>
</a>
</span>
{{/inline}}
{{#*inline "labelsLine"}}
{{#each items}}
{{> label text=(call ../display .) value=. icon=../icon type=../type item=. group=../group}}
{{/each}}
{{#if inv}}
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="fa-plus"></span> {{t (concat 'group_add_' type)}}
</button>
<ul class="dropdown-menu">
{{#each inv}}
<li><a href="#" data-type="{{../type}}s" data-operation="add" data-item="{{.}}" data-group="{{../group}}" class="group-update">{{call ../display .}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
{{/inline}}
<div id="view-permissions">
{{#each groups}}
{{#unless primary}}
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading-context-group-{{@key}}">
<h2 class="panel-title">
<a role="button" data-toggle="collapse" href="#collapse-group-{{@key}}" aria-expanded="false" aria-controls="collapse-group-{{@key}}">
<span class="fa-fw fa-group"></span> {{#if special}}{{t @key}}{{else}}{{t 'group'}} "{{ucwords @key}}"{{/if}}
</a>
</h2>
<h2 class="panel-title">
<a role="button" data-toggle="collapse" href="#collapse-group-{{@key}}" aria-expanded="false" aria-controls="collapse-group-{{@key}}">
<span class="fa-fw fa-group"></span> {{#if special}}{{t (concat 'group_' @key)}}{{else}}{{t 'group'}} "{{ucwords @key}}"{{/if}}
</a>
{{#unless special}}
<a href="#/groups/{{@key}}/delete" role="button" class="group-delete">
<span class="fa-close"></span>
<span class="sr-only">{{t 'delete'}}</span>
</a>
{{/unless}}
</h2>
</div>
<div id="collapse-group-{{@key}}" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading-context-group-{{@key}}">
<div class="panel-body">
{{#unless special}}
<div class="row">
<div class="col-sm-2">
<h3>{{t 'users'}}</h3>
</div>
<div class="col-sm-10">
{{#if special}}
<div class="alert alert-info" role="alert"><span class="fa-info-circle"></span> {{t 'perm_all_users_group_explanation'}}</div>
{{else}}
{{#each members}}
<span class="label label-default label-removable">
<span class="fa-fw fa-user"></span>
{{.}}
<span class="label-separator" aria-hidden="true">|</span>
<a role="button">
<span class="fa-close" style="margin-left:5px"></span>
<span class="sr-only">{{t 'delete'}}</span>
</a>
</span>
{{/each}}
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="fa-plus"></span> {{t 'perm_add_user'}}
</button>
<ul class="dropdown-menu">
{{#each ../users}}
<li>{{.}}</li>
{{/each}}
</ul>
</div>
{{/if}}
{{> labelsLine display=../displayUser icon="user" type="member" items=members inv=membersInv group=@key}}
</div>
</div>
<hr />
{{/unless}}
<div class="row">
<div class="col-sm-2">
<h3>{{t 'permissions'}}</h3>
</div>
<div class="col-sm-10">
{{#each permissions}}
<span class="label label-default label-removable"><span class="fa-fw fa-key-modern"></span>{{.}}
<span class="label-separator" aria-hidden="true">|</span>
<a role="button">
<span class="fa-close" style="margin-left:5px"></span>
<span class="sr-only">{{t 'delete'}}</span>
</a>
</span>
{{/each}}
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="fa-plus"></span> {{t 'perm_add_permission'}}
</button>
<ul class="dropdown-menu">
{{#each ../permissions}}
<li>{{.}}</li>
{{/each}}
</ul>
</div>
{{> labelsLine display=../displayPermission icon="key" type="permission" items=permissions inv=permissionsInv group=@key}}
{{#if special}}
<div style="font-style:italic"><span class="fa-info-circle"></span> {{t (concat 'group_' @key '_group_explanation')}}</div>
{{/if}}
</div>
</div>
</div>
</div>
</div>
{{/unless}}
{{/each}}
<div class="panel panel-info">
<div class="panel-heading" role="tab" id="heading-context-specific">
<h2 class="panel-title">
<a role="button" data-toggle="collapse" href="#collapse-specific" aria-expanded="false" aria-controls="collapse-specific">
<span class="fa-fw fa-group"></span> {{t 'perm_specific_permissions'}}
<span class="fa-fw fa-group"></span> {{t 'group_specific_permissions'}}
</a>
</h2>
</div>
<div id="collapse-specific" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading-context-specific">
<div class="panel-body">
{{#each users_with_specific_permissions}}
{{#each groups}}
{{#if (or (and primary permissions) display)}}
<div class="row">
<div class="col-sm-2">
<h3>{{@key}}</h3>
<h3><span class="fa-fw fa-user"></span> {{@key}}</h3>
</div>
<div class="col-sm-10">
{{#each permissions}}
<span class="label label-default label-removable"><span class="fa-fw fa-key-modern"></span>{{.}}
<span class="label-separator" aria-hidden="true">|</span>
<a role="button">
<span class="fa-close" style="margin-left:5px"></span>
<span class="sr-only">{{t 'delete'}}</span>
</a>
</span>
{{/each}}
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="fa-plus"></span> {{t 'perm_add_permission'}}
</button>
<ul class="dropdown-menu">
{{#each ../permissions}}
<li>{{.}}</li>
{{/each}}
</ul>
</div>
{{> labelsLine display=../displayPermission icon="key" type="permission" items=permissions inv=permissionsInv group=@key}}
</div>
</div>
<hr />
{{/if}}
{{/each}}
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="fa-plus"></span> {{t 'perm_add_user'}}
<span class="fa-plus"></span> {{t 'group_add_member'}}
</button>
<ul class="dropdown-menu">
{{#each users}}
<li>{{.}}</li>
{{#each groups}}
{{#if primary}}
{{#unless (or permissions display)}}
<li><a href="#" data-user="{{@key}}" class="group-add-user">{{@key}}</a></li>
{{/unless}}
{{/if}}
{{/each}}
</ul>
</div>