Merge branch 'develop' into 'master'
Develop merge See merge request isard/isard-sso!54
commit
d30b77926a
|
@ -629,7 +629,6 @@ class Admin():
|
|||
i=i+1
|
||||
log.warning(' KEYCLOAK GROUPS: Adding group ('+str(i)+'/'+str(total)+'): '+g)
|
||||
ev.increment({'name':g})
|
||||
print(g)
|
||||
self.keycloak.add_group_tree(g)
|
||||
|
||||
total=len(self.external['users'])
|
||||
|
@ -1170,6 +1169,22 @@ class Admin():
|
|||
|
||||
return True
|
||||
|
||||
def enable_users(self,data):
|
||||
#data={'id':'','username':''}
|
||||
ev=Events('Bulk actions','Enabling user:',total=len(data))
|
||||
for user in data:
|
||||
ev.increment({'name':user['username'],'data':user['username']})
|
||||
self.keycloak.user_enable(user['id'])
|
||||
self.resync_data()
|
||||
|
||||
def disable_users(self,data):
|
||||
#data={'id':'','username':''}
|
||||
ev=Events('Bulk actions','Disabling user:',total=len(data))
|
||||
for user in data:
|
||||
ev.increment({'name':user['username'],'data':user['username']})
|
||||
self.keycloak.user_disable(user['id'])
|
||||
self.resync_data()
|
||||
|
||||
def update_moodle_user(self,user_id,user,mdelete,madd):
|
||||
internaluser=[u for u in self.internal['users'] if u['id']==user_id][0]
|
||||
cohorts=self.moodle.get_cohorts()
|
||||
|
@ -1244,6 +1259,13 @@ class Admin():
|
|||
except:
|
||||
log.error(traceback.format_exc())
|
||||
|
||||
def delete_users(self,data):
|
||||
ev=Events('Bulk actions','Deleting users:',total=len(data))
|
||||
for user in data:
|
||||
ev.increment({'name':user['username'],'data':user['username']})
|
||||
self.delete_user(user['id'])
|
||||
self.resync_data()
|
||||
|
||||
def delete_user(self,userid):
|
||||
log.warning('Deleting user moodle, nextcloud keycloak')
|
||||
ev=Events('Deleting user','Deleting from moodle')
|
||||
|
@ -1278,7 +1300,6 @@ class Admin():
|
|||
else:
|
||||
pathpart=pathpart+'.'+part
|
||||
pathslist.append(pathpart)
|
||||
print(pathslist)
|
||||
|
||||
### KEYCLOAK
|
||||
#######################
|
||||
|
|
|
@ -197,6 +197,16 @@ class KeycloakClient():
|
|||
self.connect()
|
||||
return self.keycloak_admin.update_user( user_id, payload)
|
||||
|
||||
def user_enable(self,user_id):
|
||||
payload={"enabled":True}
|
||||
self.connect()
|
||||
return self.keycloak_admin.update_user( user_id, payload)
|
||||
|
||||
def user_disable(self,user_id):
|
||||
payload={"enabled":False}
|
||||
self.connect()
|
||||
return self.keycloak_admin.update_user( user_id, payload)
|
||||
|
||||
def group_user_remove(self,user_id,group_id):
|
||||
self.connect()
|
||||
return self.keycloak_admin.group_user_remove(user_id,group_id)
|
||||
|
|
|
@ -4,6 +4,7 @@ $(document).on('shown.bs.modal', '#modalAddDesktop', function () {
|
|||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#action_role option[value=""]').prop("selected",true);
|
||||
var path = "";
|
||||
items = [];
|
||||
document.getElementById('file-upload').addEventListener('change', readFile, false);
|
||||
|
@ -26,8 +27,8 @@ $(document).ready(function() {
|
|||
{
|
||||
console.log('SUCCESS')
|
||||
// $("#modalImport").modal('hide');
|
||||
// users_table.ajax.reload();
|
||||
// groups_table.ajax.reload();
|
||||
users_table.ajax.reload();
|
||||
groups_table.ajax.reload();
|
||||
},
|
||||
error: function(data)
|
||||
{
|
||||
|
@ -69,7 +70,7 @@ $(document).ready(function() {
|
|||
}
|
||||
});
|
||||
}).on('pnotify.cancel', function() {
|
||||
$('#action_role option[value="none"]').prop("selected",true);
|
||||
$('#action_role option[value=""]').prop("selected",true);
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -102,12 +103,14 @@ $(document).ready(function() {
|
|||
{
|
||||
console.log('SUCCESS')
|
||||
$("#modalImport").modal('hide');
|
||||
// users_table.ajax.reload();
|
||||
// groups_table.ajax.reload();
|
||||
users_table.ajax.reload();
|
||||
groups_table.ajax.reload();
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
var err = eval("(" + xhr.responseText + ")");
|
||||
alert(JSON.parse(xhr.responseText).msg)
|
||||
users_table.ajax.reload();
|
||||
groups_table.ajax.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -163,8 +166,9 @@ $(document).ready(function() {
|
|||
}
|
||||
});
|
||||
}).on('pnotify.cancel', function() {
|
||||
$('#action_role option[value="none"]').prop("selected",true);
|
||||
});
|
||||
|
||||
});
|
||||
$('#action_role option[value=""]').prop("selected",true);
|
||||
} );
|
||||
|
||||
//DataTable Main renderer
|
||||
|
|
|
@ -5,6 +5,7 @@ $(document).on('shown.bs.modal', '#modalAddDesktop', function () {
|
|||
|
||||
$(document).ready(function() {
|
||||
|
||||
$('#bulk_actions option[value=""]').prop("selected",true);
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
"url": "/api/groups",
|
||||
|
@ -29,30 +30,6 @@ $(document).ready(function() {
|
|||
}
|
||||
});
|
||||
|
||||
// $.ajax({
|
||||
// type: "GET",
|
||||
// "url": "/api/groups",
|
||||
// success: function(data)
|
||||
// {
|
||||
// data.forEach(element => {
|
||||
// var groupOrigins = [];
|
||||
// ['keycloak', 'moodle', 'nextcloud'].forEach(o => {
|
||||
// if (element[o]) {
|
||||
// groupOrigins.push(o)
|
||||
// }
|
||||
// })
|
||||
// $(".groups-select").append(
|
||||
// '<option value=' + element.path + '>' + element.name + ' (' + groupOrigins.join(',') + ') </option>'
|
||||
// )
|
||||
// });
|
||||
// $('.groups-select').select2();
|
||||
// },
|
||||
// error: function(data)
|
||||
// {
|
||||
// alert('Something went wrong on our side...')
|
||||
// }
|
||||
// });
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
"url": "/api/roles",
|
||||
|
@ -81,10 +58,68 @@ $(document).ready(function() {
|
|||
error: function(data)
|
||||
{
|
||||
alert('Something went wrong on our side...')
|
||||
table.ajax.reload();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#bulk_actions').on('change', function () {
|
||||
action=$(this).val();
|
||||
names=''
|
||||
ids=[]
|
||||
|
||||
if(table.rows('.active').data().length){
|
||||
$.each(table.rows('.active').data(),function(key, value){
|
||||
names+=value['username']+'\n';
|
||||
ids.push({'id':value['id'],'username':value['username']});
|
||||
});
|
||||
var text = "You are about to "+action+" these users:\n\n "+names
|
||||
}else{
|
||||
$.each(table.rows({filter: 'applied'}).data(),function(key, value){
|
||||
ids.push({'id':value['id'],'username':value['username']});
|
||||
});
|
||||
var text = "You are about to "+action+" "+table.rows({filter: 'applied'}).data().length+" users!\n To all the users in list!"
|
||||
}
|
||||
console.log(ids)
|
||||
new PNotify({
|
||||
title: 'Bulk actions on users',
|
||||
text: text,
|
||||
hide: false,
|
||||
opacity: 0.9,
|
||||
confirm: {
|
||||
confirm: true
|
||||
},
|
||||
buttons: {
|
||||
closer: false,
|
||||
sticker: false
|
||||
},
|
||||
history: {
|
||||
history: false
|
||||
},
|
||||
addclass: 'pnotify-center'
|
||||
}).get().on('pnotify.confirm', function() {
|
||||
$.ajax({
|
||||
type: "PUT",
|
||||
url:"/api/users_bulk/"+$('#bulk_actions').val(),
|
||||
data: JSON.stringify(ids),
|
||||
success: function(data)
|
||||
{
|
||||
console.log('SUCCESS')
|
||||
$('#bulk_actions option[value=""]').prop("selected",true);
|
||||
table.ajax.reload();
|
||||
},
|
||||
error: function(data)
|
||||
{
|
||||
alert('Something went wrong on our side...')
|
||||
$('#bulk_actions option[value=""]').prop("selected",true);
|
||||
table.ajax.reload();
|
||||
}
|
||||
});
|
||||
}).on('pnotify.cancel', function() {
|
||||
$('#bulk_actions option[value=""]').prop("selected",true);
|
||||
});
|
||||
} );
|
||||
|
||||
// Open new user modal
|
||||
$('.btn-new-user').on('click', function () {
|
||||
$("#modalAddUserForm")[0].reset();
|
||||
|
@ -281,6 +316,13 @@ $(document).ready(function() {
|
|||
<button id="btn-password" class="btn btn-xs" type="button" data-placement="top" ><i class="fa fa-lock" style="color:orange"></i></button> \
|
||||
<button id="btn-edit" class="btn btn-xs" type="button" data-placement="top" ><i class="fa fa-pencil" style="color:darkblue"></i></button>'
|
||||
},
|
||||
{
|
||||
"className": 'text-center',
|
||||
"data": null,
|
||||
"orderable": false,
|
||||
"defaultContent": '<input type="checkbox" class="form-check-input"></input>',
|
||||
"width": "10px"
|
||||
},
|
||||
{ "data": "username", "width": "10px"},
|
||||
{ "data": "first", "width": "10px"},
|
||||
{ "data": "last", "width": "150px"},
|
||||
|
@ -314,12 +356,12 @@ $(document).ready(function() {
|
|||
}
|
||||
}},
|
||||
{
|
||||
"targets": 4,
|
||||
"targets": 5,
|
||||
"render": function ( data, type, full, meta ) {
|
||||
return '<b>'+full.username+'</b>'
|
||||
}},
|
||||
{
|
||||
"targets": 8,
|
||||
"targets": 9,
|
||||
"render": function ( data, type, full, meta ) {
|
||||
grups = ''
|
||||
full.keycloak_groups.forEach(element => {
|
||||
|
@ -328,7 +370,7 @@ $(document).ready(function() {
|
|||
return grups
|
||||
}},
|
||||
{
|
||||
"targets": 9,
|
||||
"targets": 10,
|
||||
"render": function ( data, type, full, meta ) {
|
||||
if(full.quota == false){
|
||||
return 'Unlimited'
|
||||
|
@ -339,6 +381,15 @@ $(document).ready(function() {
|
|||
]
|
||||
} );
|
||||
|
||||
table.on( 'click', 'tr', function () {
|
||||
$(this).toggleClass('active');
|
||||
if ($(this).hasClass('active')) {
|
||||
$(this).find('input').prop('checked', true);
|
||||
} else {
|
||||
$(this).find('input').prop('checked', false);
|
||||
}
|
||||
} );
|
||||
|
||||
// $template = $(".template-detail-users");
|
||||
|
||||
// $('#users').find('tbody').on('click', 'td.details-control', function () {
|
||||
|
@ -406,6 +457,7 @@ $(document).ready(function() {
|
|||
error: function(data)
|
||||
{
|
||||
alert('Something went wrong on our side...')
|
||||
table.ajax.reload();
|
||||
}
|
||||
});
|
||||
}).on('pnotify.cancel', function() {
|
||||
|
@ -425,10 +477,12 @@ $(document).ready(function() {
|
|||
success: function(data)
|
||||
{
|
||||
$('#modalPasswdUserForm #password').val(data);
|
||||
table.ajax.reload();
|
||||
},
|
||||
error: function(data)
|
||||
{
|
||||
alert('Something went wrong on our side...')
|
||||
table.ajax.reload();
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
@ -455,6 +509,7 @@ $(document).ready(function() {
|
|||
error: function(data)
|
||||
{
|
||||
alert('Something went wrong on our side...')
|
||||
table.ajax.reload();
|
||||
}
|
||||
// statusCode: {
|
||||
// 404: function(data) {
|
||||
|
|
|
@ -14,6 +14,19 @@
|
|||
<div class="x_title">
|
||||
<h3><i class="fa fa-user"></i> Users</h3>
|
||||
<ul class="nav navbar-right panel_toolbox">
|
||||
<li>
|
||||
<div class="item form-group">
|
||||
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="bulk_actions">Bulk actions: <span class="required">*</span></label>
|
||||
<div class="col-md-6 col-sm-6 col-xs-12">
|
||||
<select id="bulk_actions" name="bulk_actions" class="form-control action" required>
|
||||
<option value=''>Select action</option>
|
||||
<option value='enable'>Enable</option>
|
||||
<option value='disable'>Disable</option>
|
||||
<option value='delete'>Delete</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<a class="btn-new-user"><span style="color: #5499c7; "><i class="fa fa-plus"></i> Add new</span></a>
|
||||
</li>
|
||||
|
@ -28,6 +41,7 @@
|
|||
<th>Avatar</th>
|
||||
<th>Role</th>
|
||||
<th>Actions</th>
|
||||
<th>Selected</th>
|
||||
<th>Username</th>
|
||||
<th>First</th>
|
||||
<th>Last</th>
|
||||
|
@ -38,6 +52,21 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Enabled</th>
|
||||
<th>Avatar</th>
|
||||
<th>Role</th>
|
||||
<th>Actions</th>
|
||||
<th>Selected</th>
|
||||
<th>Username</th>
|
||||
<th>First</th>
|
||||
<th>Last</th>
|
||||
<th>Email</th>
|
||||
<th>Groups</th>
|
||||
<th>Quota</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -16,7 +16,7 @@ from ..lib.helpers import system_group
|
|||
|
||||
# import Queue
|
||||
import threading
|
||||
threads={}
|
||||
threads={'external':None}
|
||||
# q = Queue.Queue()
|
||||
|
||||
from keycloak.exceptions import KeycloakGetError
|
||||
|
@ -70,6 +70,51 @@ def users(provider=False):
|
|||
user['keycloak_groups'] = [g for g in user['keycloak_groups'] if not system_group(g) ]
|
||||
return json.dumps(users), 200, {'Content-Type': 'application/json'}
|
||||
|
||||
@app.route('/api/users_bulk/<action>', methods=['PUT'])
|
||||
@login_required
|
||||
def users_bulk(action):
|
||||
data=request.get_json(force=True)
|
||||
if request.method == 'PUT':
|
||||
if action == 'enable':
|
||||
if 'external' in threads.keys():
|
||||
if threads['external'] is not None and threads['external'].is_alive():
|
||||
return json.dumps({'msg':'Precondition failed: already operating users'}), 412, {'Content-Type': 'application/json'}
|
||||
else:
|
||||
threads['external']=None
|
||||
try:
|
||||
threads['external'] = threading.Thread(target=app.admin.enable_users, args=(data,))
|
||||
threads['external'].start()
|
||||
return json.dumps({}), 200, {'Content-Type': 'application/json'}
|
||||
except:
|
||||
log.error(traceback.format_exc())
|
||||
return json.dumps({'msg':'Enable users error.'}), 500, {'Content-Type': 'application/json'}
|
||||
if action == 'disable':
|
||||
if 'external' in threads.keys():
|
||||
if threads['external'] is not None and threads['external'].is_alive():
|
||||
return json.dumps({'msg':'Precondition failed: already operating users'}), 412, {'Content-Type': 'application/json'}
|
||||
else:
|
||||
threads['external']=None
|
||||
try:
|
||||
threads['external'] = threading.Thread(target=app.admin.disable_users, args=(data,))
|
||||
threads['external'].start()
|
||||
return json.dumps({}), 200, {'Content-Type': 'application/json'}
|
||||
except:
|
||||
log.error(traceback.format_exc())
|
||||
return json.dumps({'msg':'Disabling users error.'}), 500, {'Content-Type': 'application/json'}
|
||||
if action == 'delete':
|
||||
if 'external' in threads.keys():
|
||||
if threads['external'] is not None and threads['external'].is_alive():
|
||||
return json.dumps({'msg':'Precondition failed: already operating users'}), 412, {'Content-Type': 'application/json'}
|
||||
else:
|
||||
threads['external']=None
|
||||
try:
|
||||
threads['external'] = threading.Thread(target=app.admin.delete_users, args=(data,))
|
||||
threads['external'].start()
|
||||
return json.dumps({}), 200, {'Content-Type': 'application/json'}
|
||||
except:
|
||||
log.error(traceback.format_exc())
|
||||
return json.dumps({'msg':'Deleting users error.'}), 500, {'Content-Type': 'application/json'}
|
||||
return json.dumps({}), 405, {'Content-Type': 'application/json'}
|
||||
|
||||
# Update pwd
|
||||
@app.route('/api/user_password', methods=['GET'])
|
||||
|
@ -219,11 +264,15 @@ def external():
|
|||
@app.route('/api/external/users')
|
||||
@login_required
|
||||
def external_users_list():
|
||||
while threads['external'] is not None and threads['external'].is_alive():
|
||||
time.sleep(.5)
|
||||
return json.dumps(app.admin.get_external_users()), 200, {'Content-Type': 'application/json'}
|
||||
|
||||
@app.route('/api/external/groups')
|
||||
@login_required
|
||||
def external_groups_list():
|
||||
while threads['external'] is not None and threads['external'].is_alive():
|
||||
time.sleep(.5)
|
||||
return json.dumps(app.admin.get_external_groups()), 200, {'Content-Type': 'application/json'}
|
||||
|
||||
@app.route('/api/external/roles', methods=['PUT'])
|
||||
|
|
Loading…
Reference in New Issue