Fixed avatars on deleting and UI things

root 2021-06-07 03:02:59 +02:00
parent fab77bc09e
commit 09ae3e16e6
19 changed files with 218 additions and 185 deletions

View File

@ -78,9 +78,9 @@ class Admin():
'groups':[],
'roles':[]}
log.warning(' Updating missing user avatars with defaults')
av=Avatars()
self.av=Avatars()
# av.minio_delete_all_objects() # This will reset all avatars on usres
av.update_missing_avatars(self.internal['users'])
self.av.update_missing_avatars(self.internal['users'])
log.warning(' SYSTEM READY TO HANDLE CONNECTIONS')
## This function should be moved to postup.py
@ -457,21 +457,28 @@ class Admin():
def get_dice_pwd(self):
return diceware.get_passphrase(options=options)
def reset_external(self):
self.external={'users':[],
'groups':[],
'roles':[]}
return True
def upload_json_ga(self,data):
groups=[]
log.warning('Processing uploaded groups...')
try:
ev=Events('Processing uploaded groups','Group:',total=len(data['data']['groups']))
ev=Events('Processing uploaded groups','Group:',total=len(data['data']['groups']),table='groups')
except:
log.error(traceback.format_exc())
for g in data['data']['groups']:
try:
ev.increment({'name':g['name'],'data':g})
groups.append({'provider':'external',
"id": g['id'],
"mailid": g['email'].split('@')[0],
"name": g['name'],
"description": g['description']})
group={'provider':'external',
"id": g['id'],
"mailid": g['email'].split('@')[0],
"name": g['name'],
"description": g['description']}
ev.increment({'name':g['name'],'data':group})
groups.append(group)
except:
pass
self.external['groups']=groups
@ -480,7 +487,7 @@ class Admin():
users=[]
total=len(data['data']['users'])
item=1
ev=Events('Processing uploaded users','User:',total=len(data['data']['users']))
ev=Events('Processing uploaded users','User:',total=len(data['data']['users']),table='users')
for u in data['data']['users']:
log.warning('Processing ('+str(item)+'/'+str(total)+') uploaded user: '+u['primaryEmail'].split('@')[0])
new_user={'provider':'external',
@ -491,7 +498,7 @@ class Admin():
'username': u['primaryEmail'].split('@')[0],
'groups':[u['orgUnitPath']], ## WARNING: Removing the first
'roles':[],
'password': diceware.get_passphrase(options=options)}
'password': self.get_dice_pwd()}
users.append(new_user)
item+=1
ev.increment({'name':u['primaryEmail'].split('@')[0],'data':new_user})
@ -539,7 +546,7 @@ class Admin():
log.warning(' KEYCLOAK USERS: Adding user ('+str(index)+'/'+str(total)+'): '+u['username'])
ev.increment({'name':u['username'],'data':u})
uid=self.keycloak.add_user(u['username'],u['first'],u['last'],u['email'],u['password'])
self.av.add_user_default_avatar(uid,u['roles'][0])
# Add user to role and group rolename
if len(u['roles']) != 0:
log.warning(' KEYCLOAK USERS: Assign user '+u['username']+' with initial pwd '+ u['password']+' to role '+u['roles'][0])
@ -686,6 +693,8 @@ class Admin():
except:
log.error(traceback.format_exc())
log.warning('Could not remove users: '+user['username'])
self.av.delete_user_avatar(userid)
def delete_keycloak_users(self):
total=len(self.internal['users'])
@ -702,6 +711,7 @@ class Admin():
self.keycloak.delete_user(u['id'])
except:
log.warning(' KEYCLOAK USERS: Could not remove user: '+u['username'] +'. Probably already not exists.')
self.av.minio_delete_all_objects()
def delete_nextcloud_user(self,userid):
user=[u for u in self.internal['users'] if u['id']==userid]

View File

@ -21,6 +21,16 @@ class Avatars():
self._minio_set_realm()
# self.update_missing_avatars()
def add_user_default_avatar(self,userid,role='unknown'):
self.mclient.fput_object(
self.bucket, userid, os.path.join(app.root_path,"../custom/avatars/"+role+'.jpg'),
content_type="image/jpeg ",
)
log.warning(' AVATARS: Updated avatar for user '+userid+' with role '+role)
def delete_user_avatar(self,userid):
self.minio_delete_object(userid)
def update_missing_avatars(self,users):
sys_roles=['admin','manager','teacher','student']
for u in self.get_users_without_image(users):
@ -49,7 +59,12 @@ class Avatars():
)
errors=self.mclient.remove_objects(self.bucket, delete_object_list)
for error in errors:
log.error(" AVATARS: Error occured when deleting avatar object", error)
log.error(" AVATARS: Error occured when deleting avatar object: "+ error)
def minio_delete_object(self,oid):
errors=self.mclient.remove_objects(self.bucket, [DeleteObject(oid)])
for error in errors:
log.error(" AVATARS: Error occured when deleting avatar object: "+ error)
def get_users_without_image(self,users):
return [u for u in users if u['id'] and u['id'] not in self.minio_get_objects()]

View File

@ -14,11 +14,12 @@ from flask_socketio import SocketIO, emit, join_room, leave_room, \
import base64
class Events():
def __init__(self,title,text='',total=0):
def __init__(self,title,text='',total=0,table=False):
self.eid=str(base64.b64encode(os.urandom(32))[:8])
self.title=title
self.text=text
self.total=total
self.table=table
self.item=0
self.create()
@ -61,12 +62,13 @@ class Events():
def increment(self,data={'name':'','data':[]}):
self.item+=1
log.info('INCREMENT '+self.eid+': '+self.text)
app.socketio.emit('notify-update',
app.socketio.emit('notify-increment',
json.dumps({'id':self.eid,
'title':self.title,
'text': '['+str(self.item)+'/'+str(self.total)+'] '+self.text+' '+data['name'],
'item':self.item,
'total':self.total,
'table':self.table,
'data':data}),
namespace='/sio',
room='admin')
@ -75,12 +77,13 @@ class Events():
def decrement(self,data={'name':'','data':[]}):
self.item-=1
log.info('DECREMENT '+self.eid+': '+self.text)
app.socketio.emit('notify-update',
app.socketio.emit('notify-decrement',
json.dumps({'id':self.eid,
'title':self.title,
'text': '['+str(self.item)+'/'+str(self.total)+'] '+self.text+' '+data['name'],
'item':self.item,
'total':self.total,
'table':self.table,
'data':data}),
namespace='/sio',
room='admin')

View File

@ -268,12 +268,12 @@ class KeycloakClient():
## Add user
uid=self.add_user(username,first,last,email,password)
## Add user to role
print('User uid: '+str(uid)+ ' role: '+str(role))
log.info('User uid: '+str(uid)+ ' role: '+str(role))
try:
therole=role[0]
except:
therole=''
print(self.assign_realm_roles(uid,role))
log.info(self.assign_realm_roles(uid,role))
## Create groups in user
for g in groups:
log.warning('Creating keycloak group: '+g)

View File

@ -97,7 +97,6 @@ class Moodle():
(headers,users)=self.moodle_pg.select_with_headers(q)
users_with_lists = [list(l[:-2])+([[]] if l[-2] == [None] else [list(set(l[-2]))]) + ([[]] if l[-1] == [None] else [list(set(l[-1]))]) for l in users]
list_dict_users = [dict(zip(headers, r)) for r in users_with_lists]
pprint(list_dict_users)
return list_dict_users
## NOT USED. Too slow

View File

@ -3,7 +3,6 @@
import time
from admin import app
from datetime import datetime, timedelta
import pprint
import logging as log
import traceback

View File

@ -296,8 +296,6 @@ class Nextcloud():
try:
result = json.loads(self._request('GET',url))
if result['ocs']['meta']['statuscode'] == 100: return [g for g in result['ocs']['data']['groups']]
import pprint
pprint.pprint(result)
raise ProviderOpError
except:
log.error(traceback.format_exc())

View File

@ -3,7 +3,6 @@
import time
from admin import app
from datetime import datetime, timedelta
import pprint
import logging as log
import traceback

View File

@ -3,7 +3,6 @@
import time, os
from admin import app
from datetime import datetime, timedelta
import pprint
import logging as log
import traceback

View File

@ -292,6 +292,7 @@ function dtUpdateInsertoLD(table, data, append){
}
function dtUpdateInsert(table, data, append){
table=$("#"+table).DataTable()
//Quickly appends new data rows. Does not update rows
new_id=false
if(append == true){

View File

@ -30,7 +30,7 @@ socket.on('notify-destroy', function(data) {
notice[data.id].remove()
});
socket.on('notify-update', function(data) {
socket.on('notify-increment', function(data) {
var data = JSON.parse(data);
if(!( data.id in notice)){
notice[data.id] = new PNotify({
@ -43,8 +43,13 @@ socket.on('notify-update', function(data) {
notice[data.id].update({
text: data.text
})
if(! data.table == false){
dtUpdateInsert(data.table,data['data']['data'])
}
});
// new PNotify({
// title: "Quota for creating desktops full.",
// text: "Can't create another desktop, user quota full.",

View File

@ -36,6 +36,44 @@ $(document).ready(function() {
});
});
$('.btn-clear-upload').on('click', function () {
new PNotify({
title: 'Cleaning imported data',
text: 'Are you sure you want to clean imported data?',
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: "DELETE",
url:"/api/external",
success: function(data)
{
console.log('SUCCESS')
users_table.ajax.reload();
groups_table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
}).on('pnotify.cancel', function() {
$('#action_role option[value="none"]').prop("selected",true);
});
});
$('.btn-download').on('click', function () {
data=users_table.rows().data()
@ -63,7 +101,7 @@ $(document).ready(function() {
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
$("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
},
@ -137,7 +175,7 @@ $(document).ready(function() {
},
"language": {
"loadingRecords": '<i class="fa fa-spinner fa-pulse fa-3x fa-fw"></i><span class="sr-only">Loading...</span>',
"emptyTable": "<h1>You don't have any user created yet.</h1><br><h2>Create one using the +Add new button on top right of this page.</h2>"
"emptyTable": "<h2>No users imported yet.</h2><br><h2>Import with the Upload button on top right of this page.</h2>"
},
"rowId": "id",
"deferRender": true,
@ -150,7 +188,7 @@ $(document).ready(function() {
"defaultContent": '<button class="btn btn-xs btn-info" type="button" data-placement="top" ><i class="fa fa-plus"></i></button>'
},
// { "data": "provider", "width": "10px" },
// { "data": "id", "width": "10px" },
{ "data": "id", "width": "10px" },
{ "data": "username", "width": "10px"},
{ "data": "first", "width": "10px"},
{ "data": "last", "width": "10px"},
@ -161,7 +199,13 @@ $(document).ready(function() {
],
"order": [[3, 'asc']],
"columnDefs": [ {
"targets": 5,
"targets": 1,
"render": function ( data, type, full, meta ) {
return '<img src="/custom/avatars/'+full.roles+'.jpg" title="'+full.id+'" width="25" height="25" onerror="if (this.src != \'/static/img/missing.jpg\') this.src = \'/static/img/missing.jpg\';">'
return '<img src="/avatar/'+full.id+'" title="'+full.id+'" width="25" height="25">'
}},
{
"targets": 6,
"render": function ( data, type, full, meta ) {
return "<li>" + full.groups.join("</li><li>") + "</li>"
}}
@ -176,7 +220,7 @@ $(document).ready(function() {
},
"language": {
"loadingRecords": '<i class="fa fa-spinner fa-pulse fa-3x fa-fw"></i><span class="sr-only">Loading...</span>',
"emptyTable": "<h1>You don't have any user created yet.</h1><br><h2>Create one using the +Add new button on top right of this page.</h2>"
"emptyTable": "<h2>No groups imported yet.</h2>"
},
"rowId": "id",
"deferRender": true,

View File

@ -97,58 +97,121 @@ $(document).ready(function() {
});
$('.btn-delete_keycloak').on('click', function () {
$.ajax({
type: "DELETE",
url:"/api/users/keycloak",
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
new PNotify({
title: 'Confirmation Needed',
text: "Are you sure you want to DELETE ALL USERS IN KEYCLOAK???",
hide: false,
opacity: 0.9,
confirm: {
confirm: true
},
error: function(data)
{
alert('Something went wrong on our side...')
}
buttons: {
closer: false,
sticker: false
},
history: {
history: false
},
addclass: 'pnotify-center'
}).get().on('pnotify.confirm', function() {
console.log('Updating user password...')
$.ajax({
type: "DELETE",
url:"/api/users/keycloak",
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
}).on('pnotify.cancel', function() {
});
});
$('.btn-delete_nextcloud').on('click', function () {
$.ajax({
type: "DELETE",
url:"/api/users/nextcloud",
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
new PNotify({
title: 'Confirmation Needed',
text: "Are you sure you want to DELETE ALL USERS IN NEXTCLOUD?",
hide: false,
opacity: 0.9,
confirm: {
confirm: true
},
error: function(data)
{
alert('Something went wrong on our side...')
}
buttons: {
closer: false,
sticker: false
},
history: {
history: false
},
addclass: 'pnotify-center'
}).get().on('pnotify.confirm', function() {
console.log('Updating user password...')
$.ajax({
type: "DELETE",
url:"/api/users/nextcloud",
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
}).on('pnotify.cancel', function() {
});
});
$('.btn-delete_moodle').on('click', function () {
$.ajax({
type: "DELETE",
url:"/api/users/moodle",
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
new PNotify({
title: 'Confirmation Needed',
text: "Are you sure you want to DELETE ALL USERS IN MOODLE?",
hide: false,
opacity: 0.9,
confirm: {
confirm: true
},
error: function(data)
{
alert('Something went wrong on our side...')
}
buttons: {
closer: false,
sticker: false
},
history: {
history: false
},
addclass: 'pnotify-center'
}).get().on('pnotify.confirm', function() {
console.log('Updating user password...')
$.ajax({
type: "DELETE",
url:"/api/users/moodle",
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
}).on('pnotify.cancel', function() {
});
});
$('.btn-sync_to_moodle').on('click', function () {
$.ajax({
type: "POST",

View File

@ -77,9 +77,6 @@ $(document).ready(function() {
success: function(data)
{
table.ajax.reload();
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
},
error: function(data)
{
@ -117,95 +114,6 @@ $(document).ready(function() {
// });
});
$('.btn-delete_keycloak').on('click', function () {
$.ajax({
type: "DELETE",
url:"/api/users/keycloak",
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
});
$('.btn-delete_nextcloud').on('click', function () {
$.ajax({
type: "DELETE",
url:"/api/users/nextcloud",
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
});
$('.btn-delete_moodle').on('click', function () {
$.ajax({
type: "DELETE",
url:"/api/users/moodle",
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
});
$('.btn-sync_to_moodle').on('click', function () {
$.ajax({
type: "POST",
url:"/api/users/moodle",
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
});
$('.btn-sync_to_nextcloud').on('click', function () {
$.ajax({
type: "POST",
url:"/api/users/nextcloud",
success: function(data)
{
console.log('SUCCESS')
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
});
//DataTable Main renderer
var table = $('#users').DataTable({
"ajax": {
@ -250,7 +158,7 @@ $(document).ready(function() {
"targets": 1,
"render": function ( data, type, full, meta ) {
// return '<object data="/static/img/missing.jpg" type="image/jpeg" width="25" height="25"><img src="/avatar/'+full.id+'" title="'+full.id+'" width="25" height="25"></object>'
return '<img src="/avatar/'+full.id+'" title="'+full.id+'" width="25" height="25">'
return '<img src="/avatar/'+full.id+'" title="'+full.id+'" width="25" height="25" onerror="if (this.src != \'/static/img/missing.jpg\') this.src = \'/static/img/missing.jpg\';">'
}},
{
"targets": 2,

View File

@ -16,7 +16,7 @@
</ul>
</li>
<li role="presentation" class="sync-status">
<!-- <li role="presentation" class="sync-status">
<a href="javascript:" class="dropdown-toggle info-number" data-toggle="dropdown" aria-expanded="false">
<i class="fa fa-spinner"></i>
<span class="badge"></span>
@ -45,7 +45,7 @@
</a>
</li>
</ul>
</li>
</li> -->
</ul>
</nav>
</div>

View File

@ -31,6 +31,7 @@
<a class="btn-sync"><span style="color: #5499c7; "><i class="fa fa-rocket"></i> Sync to system</span></a>
<a class="btn-upload"><span style="color: #5499c7; "><i class="fa fa-upload"></i> Upload</span></a>
<a class="btn-download"><span style="color: #5499c7; "><i class="fa fa-download"></i> Download</span></a>
<a class="btn-clear-upload"><span style="color: #5499c7; "><i class="fa fa-cross"></i> Clear upload</span></a>
</li>
</ul>
<div class="clearfix"></div>
@ -41,6 +42,7 @@
<thead>
<tr>
<th></th>
<th>Avatar</th>
<th>Username</th>
<th>First</th>
<th>Last</th>
@ -83,5 +85,5 @@
<!-- Switchery -->
<script src="/vendors/switchery/dist/switchery.min.js"></script>
<!-- Desktops sse & modals -->
<script src="/static/js/external.js"></script>
<script src="/static/js/sysadmin/external.js"></script>
{% endblock %}

View File

@ -27,7 +27,7 @@
<button class="btn btn-primary btn-xs btn-sync_to_moodle">
<i class="fa fa-refresh" aria-hidden="true"></i> Sync to Moodle
</button>
{% if current_user.role =='sysadmin' %}
{% if current_user.role =='admin' %}
<button class="btn btn-danger btn-xs btn-delete_keycloak">
<i class="fa fa-trash"></i> Delete all keycloak
</button>

View File

@ -21,23 +21,6 @@
<div class="clearfix"></div>
</div>
<div class="x_content">
{% if current_user.role =='admin' %}
<button class="btn btn-primary btn-xs btn-sync_to_nextcloud">
<i class="fa fa-refresh" aria-hidden="true"></i> Sync to Nextcloud
</button>
<button class="btn btn-primary btn-xs btn-sync_to_moodle">
<i class="fa fa-refresh" aria-hidden="true"></i> Sync to Moodle
</button>
<button class="btn btn-danger btn-xs btn-delete_keycloak">
<i class="fa fa-trash"></i> Delete all keycloak
</button>
<button class="btn btn-danger btn-xs btn-delete_nextcloud">
<i class="fa fa-trash"></i> Delete missing keycloak in nextcloud
</button>
<button class="btn btn-danger btn-xs btn-delete_moodle">
<i class="fa fa-trash"></i> Delete missing keycloak in moodle
</button>
{% endif %}
<table id="users" class="table" width="100%">
<thead>
<tr>

View File

@ -103,7 +103,7 @@ def groups(provider=False):
### SYSADM USERS ONLY
@app.route('/api/external', methods=['POST', 'PUT', 'GET'])
@app.route('/api/external', methods=['POST', 'PUT', 'GET','DELETE'])
@login_required
def external():
if 'external' in threads.keys():
@ -112,8 +112,8 @@ def external():
else:
threads['external']=None
data=request.get_json(force=True)
if request.method == 'POST':
data=request.get_json(force=True)
if data['format']=='json-ga':
threads['external'] = threading.Thread(target=app.admin.upload_json_ga, args=(data,))
threads['external'].start()
@ -123,9 +123,14 @@ def external():
threads['external'].start()
return json.dumps({}), 200, {'Content-Type': 'application/json'}
if request.method == 'PUT':
data=request.get_json(force=True)
threads['external'] = threading.Thread(target=app.admin.sync_external, args=(data,))
threads['external'].start()
return json.dumps({}), 200, {'Content-Type': 'application/json'}
if request.method == 'DELETE':
print('RESET')
app.admin.reset_external()
return json.dumps({}), 200, {'Content-Type': 'application/json'}
return json.dumps({}), 500, {'Content-Type': 'application/json'}
@app.route('/api/external/users')