add: list authorizations/grants

This commit is contained in:
ziirish 2018-03-27 18:42:34 +02:00
parent 2db3c27e3a
commit 9057b6bcd9
No known key found for this signature in database
GPG key ID: 72DB229A64B54E46
8 changed files with 294 additions and 327 deletions

View file

@ -51,8 +51,6 @@
<tr>
<th>{{ _('Username') }}</th>
<th>{{ _('Authentication Backend') }}</th>
<th>{{ _('Role') }}</th>
<th>{{ _('Groups') }}</th>
<th>{{ _('Controls') }}</th>
</tr>
</thead>

View file

@ -8,8 +8,9 @@
<li class="active">{{ _('Administration') }}</li>
</ul>
<br />
<!--
<div class="form-container">
<legend id="authentication">{{ _('Authentication') }}</legend>
<legend id="authentication">{{ _('Authorization') }}</legend>
<div class="row well">
<form action="{{ url_for('api.auth_users') }}" method="PUT" class="form-inline" name="pctrl.userAdd" ng-submit="addUser($event)">
<fieldset>
@ -36,8 +37,9 @@
</form>
</div>
</div>
-->
<div class="form-container">
<legend>{{ _('Users list') }}</legend>
<legend>{{ _('Grants list') }}</legend>
<div id="waiting-user-container" class="row">
<i class="fa fa-spin fa-fw fa-refresh" aria-hidden="true"></i>&nbsp;{{ _('Loading, Please wait...') }}
<br />
@ -50,9 +52,35 @@
<thead>
<tr>
<th>{{ _('Username') }}</th>
<th>{{ _('Authentication Backend') }}</th>
<th>{{ _('Authorization Backend') }}</th>
<th>{{ _('Role') }}</th>
<th>{{ _('Groups') }}</th>
<th>{{ _('Grants') }}</th>
<th>{{ _('Controls') }}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<div class="form-container">
<legend>{{ _('Groups list') }}</legend>
<div id="waiting-group-container" class="row">
<i class="fa fa-spin fa-fw fa-refresh" aria-hidden="true"></i>&nbsp;{{ _('Loading, Please wait...') }}
<br />
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-info" style="width: 100%"></div>
</div>
</div>
<div class="table-responsive" id="table-groups-container" style="display: none;">
<table class="table table-striped table-hover nowrap" id="table-groups" width="100%">
<thead>
<tr>
<th>{{ _('Group name') }}</th>
<th>{{ _('Authorization Backend') }}</th>
<th>{{ _('Members') }}</th>
<th>{{ _('Grants') }}</th>
<th>{{ _('Controls') }}</th>
</tr>
</thead>

View file

@ -1,101 +1,3 @@
/***
* The Settings Panel is managed with AngularJS.
* Following is the AngularJS Application and Controller.
* Our $scope is initialized with a $http request that retrieves a JSON like that:
* {
* "boolean": [
* "key",
* ...
* ],
* "defaults": {
* "key1": "default",
* "key2": false,
* "key3": [
* 4,
* 2,
* ],
* ...
* },
* "integer": [
* "key",
* ],
* "multi": [
* "key",
* ],
* "placeholders": {
* "key": "placeholder",
* ...
* },
* "results": {
* "boolean": [
* {
* "name": "key",
* "value": true
* },
* ...
* ],
* "clients": [
* {
* "name": "clientname",
* "value": "/etc/burp/clientconfdir/clientname"
* },
* ...
* ],
* "common": [
* {
* "name": "key",
* "value": "val"
* },
* ...
* ],
* "integer": [
* {
* "name": "key",
* "value": 42
* },
* ...
* ],
* "multi": [
* {
* "name": "key",
* "value": [
* "value1",
* "value2",
* ...
* ]
* },
* ...
* ],
* "includes": [
* "glob",
* "example*.conf",
* ...
* ],
* "includes_ext": [
* "glob",
* "example1.conf",
* "example_toto.conf",
* ...
* ]
* },
* "server_doc": {
* "key": "documentations of the specified key from the manpage",
* ...
* },
* "string": [
* "key",
* ...
* ],
* "suggest": {
* "key": [
* "value1",
* "value2",
* ],
* [...]
* }
* }
* The JSON is then split-ed out into several dict/arrays to build our form.
*/
{% import 'macros.html' as macros %}
var _cache_id = _EXTRA;
@ -214,26 +116,6 @@ var _users_table = $('#table-users').DataTable( {
return ret;
}
},
{
data: null,
render: function ( data, type, row ) {
var ret = '';
$.each(data.roles, function(i, role) {
ret += '<span class="label label-warning">'+role+'</span>&nbsp;';
});
return ret;
}
},
{
data: null,
render: function ( data, type, row ) {
var ret = '';
$.each(data.groups, function(i, group) {
ret += '<span class="label label-primary">'+group+'</span>&nbsp;';
});
return ret;
}
},
{
data: null,
render: function ( data, type, row ) {
@ -253,7 +135,6 @@ var _authentication = function() {
$('#table-users-container').hide();
var __usernames = [];
$.getJSON('{{ url_for("api.auth_users") }}').done(function (users) {
__promises = [];
$.each(users, function(i, user) {
__usernames.push(user.name);
if (_users[user.name]) {
@ -267,26 +148,8 @@ var _authentication = function() {
_users[user.name] = {
id: user.name,
backends: [user.backend],
roles: [],
groups: [],
raw: [user],
};
var p = $.getJSON('{{ url_for("api.acl_groups_of", member="") }}'+user.name).done(function (data) {
_users[user.name]['groups'] = data.groups;
});
__promises.push(p);
p = $.getJSON('{{ url_for("api.acl_is_admin", member="") }}'+user.name).done(function (data) {
if (data.admin) {
_users[user.name]['roles'].push('admin');
}
});
__promises.push(p);
p = $.getJSON('{{ url_for("api.acl_is_moderator", member="") }}'+user.name).done(function (data) {
if (data.moderator) {
_users[user.name]['roles'].push('moderator');
}
});
__promises.push(p);
}
});
var redraw = false;
@ -294,27 +157,14 @@ var _authentication = function() {
$.each(_users, function(key, value) {
if (__usernames.indexOf(key) == -1) {
delete _users[key];
redraw = true;
} else {
_users_array.push(value);
}
});
if (redraw) {
_users_table.clear();
_users_table.rows.add(_users_array).draw();
$('#waiting-user-container').hide();
$('#table-users-container').show();
}
$.when.apply( $, __promises ).done(function() {
_users_array = [];
$.each(_users, function(key, value) {
_users_array.push(value);
});
_users_table.clear();
_users_table.rows.add(_users_array).draw();
$('#waiting-user-container').hide();
$('#table-users-container').show();
});
_users_table.clear();
_users_table.rows.add(_users_array).draw();
$('#waiting-user-container').hide();
$('#table-users-container').show();
});
};

View file

@ -1,107 +1,10 @@
/***
* The Settings Panel is managed with AngularJS.
* Following is the AngularJS Application and Controller.
* Our $scope is initialized with a $http request that retrieves a JSON like that:
* {
* "boolean": [
* "key",
* ...
* ],
* "defaults": {
* "key1": "default",
* "key2": false,
* "key3": [
* 4,
* 2,
* ],
* ...
* },
* "integer": [
* "key",
* ],
* "multi": [
* "key",
* ],
* "placeholders": {
* "key": "placeholder",
* ...
* },
* "results": {
* "boolean": [
* {
* "name": "key",
* "value": true
* },
* ...
* ],
* "clients": [
* {
* "name": "clientname",
* "value": "/etc/burp/clientconfdir/clientname"
* },
* ...
* ],
* "common": [
* {
* "name": "key",
* "value": "val"
* },
* ...
* ],
* "integer": [
* {
* "name": "key",
* "value": 42
* },
* ...
* ],
* "multi": [
* {
* "name": "key",
* "value": [
* "value1",
* "value2",
* ...
* ]
* },
* ...
* ],
* "includes": [
* "glob",
* "example*.conf",
* ...
* ],
* "includes_ext": [
* "glob",
* "example1.conf",
* "example_toto.conf",
* ...
* ]
* },
* "server_doc": {
* "key": "documentations of the specified key from the manpage",
* ...
* },
* "string": [
* "key",
* ...
* ],
* "suggest": {
* "key": [
* "value1",
* "value2",
* ],
* [...]
* }
* }
* The JSON is then split-ed out into several dict/arrays to build our form.
*/
{% import 'macros.html' as macros %}
var _cache_id = _EXTRA;
var _me = undefined;
var _users = {};
var _groups = {};
var _auth_backends = {};
var _users_array = [];
var __promises = [];
@ -117,7 +20,7 @@ app.controller('AdminCtrl', ['$scope', '$http', '$scrollspy', 'DTOptionsBuilder'
var vm = this;
$scope.auth_backends = [];
$http.get('{{ url_for("api.auth_backends") }}', { headers: { 'X-From-UI': true } })
$http.get('{{ url_for("api.acl_backends") }}', { headers: { 'X-From-UI': true } })
.then(function (response) {
$scope.auth_backends = [];
_auth_backends = {};
@ -126,8 +29,10 @@ app.controller('AdminCtrl', ['$scope', '$http', '$scrollspy', 'DTOptionsBuilder'
$scope.auth_backends.push(back);
});
$scope.auth_backend = "placeholder";
/*
vm.userAdd.auth_backend.$setValidity('valid', false);
vm.userAdd.$setPristine();
*/
});
$scope.checkSelect = function() {
@ -171,6 +76,82 @@ app.controller('AdminCtrl', ['$scope', '$http', '$scrollspy', 'DTOptionsBuilder'
};
}]);
var _groups_table = $('#table-groups').DataTable( {
{{ macros.translate_datatable() }}
{{ macros.get_page_length() }}
responsive: true,
processing: true,
fixedHeader: true,
select: {
style: 'os',
},
data: [],
rowId: 'id',
rowCallback: function( row, data, index ) {
var classes = row.className.split(' ');
_.each(classes, function(cl) {
if (_.indexOf(['odd', 'even'], cl) != -1) {
row.className = cl;
return;
}
});
if (data.id === _me.name) {
row.className += ' success';
}
},
columns: [
{
data: 'id',
},
{
data: 'backends',
render: function ( data, type, row ) {
if (type === 'filter' || type === 'sort') {
return data;
}
var ret = '';
$.each(data, function(i, back) {
ret += '<span class="label label-default">'+back+'</span>&nbsp;';
});
return ret;
}
},
{
data: 'members',
render: function ( data, type, row ) {
if (type === 'filter' || type === 'sort') {
return data.length+'-'+data.join(',');
}
return '<span class="badge" data-toggle="tooltip" title="'+data.join(', ')+'">'+data.length+'</span>';
}
},
{
data: 'grants',
render: function ( data, type, row ) {
if (type === 'filter' || type === 'sort') {
return data;
}
var ret = '';
$.each(data, function(i, grant) {
ret += '<code data-toggle="tooltip" data-html="true" title="<code>'+grant.replace(/\"/g,'&quot;')+'</code>">'+$.trim(grant).substring(0, 20).split(' ').slice(0, -1).join(" ")+'...</code>&nbsp;';
});
return ret;
}
},
{
data: null,
orderable: false,
render: function ( data, type, row ) {
return '<button data-member="'+data.id+'" class="btn btn-xs btn-danger btn-delete-user" title="{{ _("Remove") }}"><i class="fa fa-trash" aria-hidden="true"></i></button>&nbsp;<button data-member="'+data.id+'" class="btn btn-xs btn-info btn-edit-user" title="{{ _("Edit") }}"><i class="fa fa-pencil" aria-hidden="true"></i></button>';
}
},
],
});
_groups_table.on('draw.dt', function() {
$('[data-toggle="tooltip"]').tooltip();
});
var _users_table = $('#table-users').DataTable( {
{{ macros.translate_datatable() }}
{{ macros.get_page_length() }}
@ -190,105 +171,132 @@ var _users_table = $('#table-users').DataTable( {
return;
}
});
_.each(data.raw, function(raw) {
if (raw.name === _me.name && raw.backend == _me.backend) {
row.className += ' success';
return;
}
});
if (data.id === _me.name) {
row.className += ' success';
}
},
columns: [
{
data: null,
render: function ( data, type, row ) {
return data.id;
}
data: 'id',
},
{
data: null,
data: 'backends',
render: function ( data, type, row ) {
if (type === 'filter' || type === 'sort') {
return data;
}
var ret = '';
$.each(data.backends, function(i, back) {
$.each(data, function(i, back) {
ret += '<span class="label label-default">'+back+'</span>&nbsp;';
});
return ret;
}
},
{
data: null,
data: 'roles',
render: function ( data, type, row ) {
if (type === 'filter' || type === 'sort') {
return data;
}
var ret = '';
$.each(data.roles, function(i, role) {
$.each(data, function(i, role) {
ret += '<span class="label label-warning">'+role+'</span>&nbsp;';
});
return ret;
}
},
{
data: null,
data: 'groups',
render: function ( data, type, row ) {
if (type === 'filter' || type === 'sort') {
return data;
}
var ret = '';
$.each(data.groups, function(i, group) {
$.each(data, function(i, group) {
ret += '<span class="label label-primary">'+group+'</span>&nbsp;';
});
return ret;
}
},
{
data: null,
data: 'grants',
render: function ( data, type, row ) {
return '<button data-member="'+data.id+'" class="btn btn-xs btn-danger btn-delete-user" title="{{ _("Remove") }}"><i class="fa fa-trash" aria-hidden="true"></i></button>&nbsp;<button data-member="'+data.id+'" class="btn btn-xs btn-info btn-edit-user" title="{{ _("Edit") }}"><i class="fa fa-pencil" aria-hidden="true"></i></button>&nbsp;<button data-member="'+data.id+'" class="btn btn-xs btn-warning btn-sessions-user" title="{{ _("Sessions") }}"><i class="fa fa-list-alt" aria-hidden="true"></i></button>';
if (type === 'filter' || type === 'sort') {
return data;
}
var ret = '';
$.each(data, function(i, grant) {
ret += '<code data-toggle="tooltip" data-html="true" title="<code>'+grant.replace(/\"/g,'&quot;')+'</code>">'+$.trim(grant).substring(0, 20).split(' ').slice(0, -1).join(" ")+'...</code>&nbsp;';
});
return ret;
}
},
{
data: null,
orderable: false,
render: function ( data, type, row ) {
return '<button data-member="'+data.id+'" class="btn btn-xs btn-danger btn-delete-user" title="{{ _("Remove") }}"><i class="fa fa-trash" aria-hidden="true"></i></button>&nbsp;<button data-member="'+data.id+'" class="btn btn-xs btn-info btn-edit-user" title="{{ _("Edit") }}"><i class="fa fa-pencil" aria-hidden="true"></i></button>';
}
},
],
});
_users_table.on('draw.dt', function() {
$('[data-toggle="tooltip"]').tooltip();
});
var g = $.getJSON('{{ url_for("api.admin_me") }}').done(function (data) {
_me = data;
});
__globals_promises.push(g);
var _authentication = function() {
var _authorization_users = function() {
$('#waiting-user-container').show();
$('#table-users-container').hide();
var __usernames = [];
$.getJSON('{{ url_for("api.auth_users") }}').done(function (users) {
var __top_promises = [];
var t = $.getJSON('{{ url_for("api.acl_grants") }}').done(function (grants) {
__promises = [];
$.each(users, function(i, user) {
__usernames.push(user.name);
if (_users[user.name]) {
if (_users[user.name]['backends'].indexOf(user.backend) === -1) {
_users[user.name]['backends'].push(user.backend);
$.each(grants, function(i, user) {
__usernames.push(user.id);
if (_users[user.id]) {
if (_users[user.id]['backends'].indexOf(user.backend) === -1) {
_users[user.id]['backends'].push(user.backend);
}
if (_users[user.name]['raw'].indexOf(user) === -1) {
_users[user.name]['raw'].push(user);
if (_users[user.id]['grants'].indexOf(user.grant) === -1) {
_users[user.id]['grants'].push(user.grant);
}
if (_users[user.id]['raw'].indexOf(user) === -1) {
_users[user.id]['raw'].push(user);
}
} else {
_users[user.name] = {
id: user.name,
_users[user.id] = {
id: user.id,
backends: [user.backend],
roles: [],
groups: [],
grants: [user.grant],
raw: [user],
};
var p = $.getJSON('{{ url_for("api.acl_groups_of", member="") }}'+user.name).done(function (data) {
_users[user.name]['groups'] = data.groups;
var p = $.getJSON('{{ url_for("api.acl_groups_of", member="") }}'+user.id).done(function (data) {
_users[user.id]['groups'] = data.groups;
});
__promises.push(p);
p = $.getJSON('{{ url_for("api.acl_is_admin", member="") }}'+user.name).done(function (data) {
p = $.getJSON('{{ url_for("api.acl_is_admin", member="") }}'+user.id).done(function (data) {
if (data.admin) {
_users[user.name]['roles'].push('admin');
_users[user.id]['roles'].push('admin');
}
});
__promises.push(p);
p = $.getJSON('{{ url_for("api.acl_is_moderator", member="") }}'+user.name).done(function (data) {
p = $.getJSON('{{ url_for("api.acl_is_moderator", member="") }}'+user.id).done(function (data) {
if (data.moderator) {
_users[user.name]['roles'].push('moderator');
_users[user.id]['roles'].push('moderator');
}
});
__promises.push(p);
}
});
__top_promises.push(t);
var redraw = false;
_users_array = [];
$.each(_users, function(key, value) {
@ -305,21 +313,83 @@ var _authentication = function() {
$('#waiting-user-container').hide();
$('#table-users-container').show();
}
$.when.apply( $, __promises ).done(function() {
_users_array = [];
$.each(_users, function(key, value) {
_users_array.push(value);
$.when.apply( $, __top_promises ).done(function() {
$.when.apply( $, __promises ).done(function() {
_users_array = [];
$.each(_users, function(key, value) {
_users_array.push(value);
});
_users_table.clear();
_users_table.rows.add(_users_array).draw();
$('#waiting-user-container').hide();
$('#table-users-container').show();
});
_users_table.clear();
_users_table.rows.add(_users_array).draw();
$('#waiting-user-container').hide();
$('#table-users-container').show();
});
});
};
var _authorization_groups = function() {
$('#waiting-group-container').show();
$('#table-groups-container').hide();
var __groupnames = [];
var __top_promises = [];
var t = $.getJSON('{{ url_for("api.acl_groups") }}').done(function (groups) {
$.each(groups, function(i, group) {
__groupnames.push(group.id);
if (_groups[group.id]) {
if (_groups[group.id]['backends'].indexOf(group.backend) === -1) {
_groups[group.id]['backends'].push(group.backend);
}
if (_groups[group.id]['grants'].indexOf(group.grant) === -1) {
_groups[group.id]['grants'].push(group.grant);
}
if (_groups[group.id]['raw'].indexOf(group) === -1) {
_groups[group.id]['raw'].push(group);
}
_groups[group.id]['members'] = _.merge(_groups[group.id]['members'], group.members);
} else {
_groups[group.id] = {
id: group.id,
backends: [group.backend],
members: group.members,
grants: [group.grant],
raw: [group],
};
}
});
__top_promises.push(t);
var redraw = false;
_groups_array = [];
$.each(_groups, function(key, value) {
if (__groupnames.indexOf(key) == -1) {
delete _groups[key];
redraw = true;
} else {
_groups_array.push(value);
}
});
if (redraw) {
_groups_table.clear();
_groups_table.rows.add(_groups_array).draw();
$('#waiting-group-container').hide();
$('#table-groups-container').show();
}
$.when.apply( $, __top_promises ).done(function() {
_groups_array = [];
$.each(_groups, function(key, value) {
_groups_array.push(value);
});
_groups_table.clear();
_groups_table.rows.add(_groups_array).draw();
$('#waiting-group-container').hide();
$('#table-groups-container').show();
});
});
};
var _admin = function() {
_authentication();
_authorization_users();
_authorization_groups();
};
{{ macros.page_length('#table-list-clients') }}

View file

@ -98,42 +98,46 @@ var _client_table = $('#table-client').DataTable( {
{
data: null,
render: function ( data, type, row ) {
return '<a href="{{ url_for("view.client_browse", name=cname, server=server) }}?backup='+data.number+(data.encrypted?'&encrypted=1':'')+'" style="color: inherit; text-decoration: inherit;">'+pad(data.number, 7)+'</a>';
if (type === 'filter' || type === 'sort') {
return data.number;
}
return '<a href="{{ url_for("view.client_browse", name=cname, server=server) }}/'+data.number+(data.encrypted?'&encrypted=1':'')+'" style="color: inherit; text-decoration: inherit;">'+pad(data.number, 7)+'</a>';
}
},
{
data: null,
data: 'date',
type: 'timestamp',
render: function ( data, type, row ) {
return '<span data-toggle="tooltip" title="'+data.date+'">'+moment(data.date, moment.ISO_8601).format({{ g.date_format|tojson }})+'</span>';
return '<span data-toggle="tooltip" title="'+data+'">'+moment(data, moment.ISO_8601).format({{ g.date_format|tojson }})+'</span>';
}
},
{
data: null,
data: 'received',
render: function ( data, type, row ) {
return _bytes_human_readable(data.received, false);
return _bytes_human_readable(data, false);
}
},
{
data: null,
data: 'size',
render: function ( data, type, row ) {
return _bytes_human_readable(data.size, false);
return _bytes_human_readable(data, false);
}
},
{
data: null,
data: 'deletable',
render: function ( data, type, row ) {
return '<i class="fa fa-'+(data.deletable?'check':'remove')+'" aria-hidden="true"></i>';
return '<i class="fa fa-'+(data?'check':'remove')+'" aria-hidden="true"></i>';
}
},
{
data: null,
data: 'encrypted',
render: function ( data, type, row ) {
return '<i class="fa fa-fw fa-'+(data.encrypted?'lock':'globe')+'" aria-hidden="true"></i>&nbsp;'+(data.encrypted?"{{ _('Encrypted backup') }}":"{{ _('Unencrypted backup') }}");
return '<i class="fa fa-fw fa-'+(data?'lock':'globe')+'" aria-hidden="true"></i>&nbsp;'+(data?"{{ _('Encrypted backup') }}":"{{ _('Unencrypted backup') }}");
}
},
{
data: null,
orderable: false,
render: function ( data, type, row ) {
var disable = '';
if (!data.deletable) {

View file

@ -100,9 +100,12 @@ var _clients_table = $('#table-clients').DataTable( {
},
columns: [
{
data: null,
data: 'name',
render: function ( data, type, row ) {
return '<a href="{{ url_for("view.client", server=server) }}?name='+data.name+'" style="color: inherit; text-decoration: inherit;">'+data.name+'</a>';
if (type === 'filter' || type === 'sort') {
return data;
}
return '<a href="{{ url_for("view.client", server=server, name="") }}'+data+'" style="color: inherit; text-decoration: inherit;">'+data+'</a>';
}
},
{
@ -121,22 +124,25 @@ var _clients_table = $('#table-clients').DataTable( {
}
},
{
data: null,
data: 'last',
type: 'timestamp',
render: function (data, type, row ) {
if (!(data.last in __status || data.last in __date))
return '<span data-toggle="tooltip" title="'+data.last+'">'+moment(data.last, moment.ISO_8601).format({{ g.date_format|tojson }})+'</span>';
return data.last
if (!(data in __status || data in __date))
return '<span data-toggle="tooltip" title="'+data+'">'+moment(data, moment.ISO_8601).format({{ g.date_format|tojson }})+'</span>';
return data
}
},
{
data: null,
data: 'labels',
render: function (data, type, row) {
if (type === 'filter' || type === 'sort') {
return data;
}
var ret = '';
if (!data.labels) {
if (!data) {
return ret;
}
$.each(data.labels, function(i, label) {
$.each(data, function(i, label) {
ret += '<span class="label label-info">'+label+'</span>&nbsp;';
});
return ret;
@ -144,6 +150,7 @@ var _clients_table = $('#table-clients').DataTable( {
},
{
data: null,
orderable: false,
render: function (data, type, row ) {
var cls = '';
var link_start = '';

View file

@ -37,7 +37,12 @@ var _servers_table = $('#table-servers').DataTable( {
row.className += ' clickable';
},
columns: [
{ data: null, render: function ( data, type, row ) {
{
data: null,
render: function ( data, type, row ) {
if (type === 'filter' || type === 'sort') {
return data.name;
}
href = '{{ url_for("view.clients") }}?serverName='+data.name;
if (!data.alive) {
href = '#';
@ -46,9 +51,14 @@ var _servers_table = $('#table-servers').DataTable( {
}
},
{ data: 'clients' },
{ data: null, render: function (data, type, row ) {
{
data: 'alive',
render: function (data, type, row ) {
if (type === 'filter' || type === 'sort') {
return data;
}
glyph = 'fa-check';
if (!data.alive) {
if (!data) {
glyph = 'fa-remove';
}
return '<i class="fa '+glyph+'"></i>';

View file

@ -2,7 +2,7 @@
<div id="navbar-config">
<h4>{{ _('Administration navigation') }}</h4>
<ul class="nav nav-sidebar">
<li class="active"><a href="{{ url_for('view.admin_authentications') }}">{{ _('Authentication') }}</a></li>
<li><a href="{{ url_for('view.admin_authorizations') }}">{{ _('Authorization') }}</a></li>
<li {% if authentications %}class="active"{% endif %}><a href="{{ url_for('view.admin_authentications') }}">{{ _('Authentication') }}</a></li>
<li {% if authorizations %}class="active"{% endif %}><a href="{{ url_for('view.admin_authorizations') }}">{{ _('Authorization') }}</a></li>
</ul>
</div>