updated admin functs

root 2021-06-06 22:05:12 +02:00
parent a65441bc03
commit 90ef56bbdf
41 changed files with 1368 additions and 599 deletions

View File

@ -16,7 +16,7 @@ You can generate one with:
os.urandom(24)
And paste it here.
'''
app.secret_key = "Change this key!//\xf7\x83\xbe\x17\xfa\xa3zT\n\\]m\xa6\x8bF\xdd\r\xf7\x9e\x1d\x1f\x14'"
app.secret_key = "Change this key!/\xf7\x83\xbe\x17\xfa\xa3zT\n\\]m\xa6\x8bF\xdd\r\xf7\x9e\x1d\x1f\x14'"
print('Starting isard-sso api...')
@ -45,15 +45,15 @@ else:
'''
Serve static files
'''
@app.route('/isard-sso-admin/build/<path:path>')
@app.route('/build/<path:path>')
def send_build(path):
return send_from_directory(os.path.join(app.root_path, 'node_modules/gentelella/build'), path)
@app.route('/isard-sso-admin/vendors/<path:path>')
@app.route('/vendors/<path:path>')
def send_vendors(path):
return send_from_directory(os.path.join(app.root_path, 'node_modules/gentelella/vendors'), path)
@app.route('/isard-sso-admin/templates/<path:path>')
@app.route('/templates/<path:path>')
def send_templates(path):
return send_from_directory(os.path.join(app.root_path, 'templates'), path)
@ -61,14 +61,18 @@ def send_templates(path):
# def send_templates(path):
# return send_from_directory(os.path.join(app.root_path, 'static/templates'), path)
@app.route('/isard-sso-admin/static/<path:path>')
@app.route('/static/<path:path>')
def send_static_js(path):
return send_from_directory(os.path.join(app.root_path, 'static'), path)
@app.route('/isard-sso-admin/avatars/<path:path>')
@app.route('/avatars/<path:path>')
def send_avatars_img(path):
return send_from_directory(os.path.join(app.root_path, '../avatars/master-avatars'), path)
@app.route('/custom/<path:path>')
def send_custom(path):
return send_from_directory(os.path.join(app.root_path, '../custom'), path)
# @app.errorhandler(404)
# def not_found_error(error):
# return render_template('page_404.html'), 404
@ -81,8 +85,8 @@ def send_avatars_img(path):
Import all views
'''
from .views import LoginViews
from .views import MenuViews
from .views import AvatarViews
from .views import WebViews
from .views import ApiViews

View File

@ -1,31 +1,28 @@
from admin import app
from flask_login import LoginManager, UserMixin
from flask_login import login_required
from flask_oidc import OpenIDConnect
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"
app.config.update({
'SECRET_KEY': 'u\x91\xcf\xfa\x0c\xb9\x95\xe3t\xba2K\x7f\xfd\xca\xa3\x9f\x90\x88\xb8\xee\xa4\xd6\xe4',
'TESTING': True,
'DEBUG': True,
'OIDC_CLIENT_SECRETS': 'client_secrets.json',
'OIDC_ID_TOKEN_COOKIE_SECURE': False,
'OIDC_REQUIRE_VERIFIED_EMAIL': False,
'OIDC_VALID_ISSUERS': ['https://sso.santantoni.duckdns.org:8080/auth/realms/master'],
'OIDC_OPENID_REALM': 'https://sso.santantoni.duckdns.org/isard-sso-admin/custom_callback',
'OVERWRITE_REDIRECT_URI': 'https://sso.santantoni.duckdns.org/isard-sso-admin/custom_callback',
})
# 'OVERWRITE_REDIRECT_URI': 'https://sso.santantoni.duckdns.org/isard-sso-admin/custom_callback',
# 'OIDC_CALLBACK_ROUTE': '/isard-sso-admin/custom_callback'
oidc = OpenIDConnect(app)
import os
# login_manager = LoginManager()
# login_manager.init_app(app)
''' OIDC TESTS '''
# from flask_oidc import OpenIDConnect
# app.config.update({
# 'SECRET_KEY': 'u\x91\xcf\xfa\x0c\xb9\x95\xe3t\xba2K\x7f\xfd\xca\xa3\x9f\x90\x88\xb8\xee\xa4\xd6\xe4',
# 'TESTING': True,
# 'DEBUG': True,
# 'OIDC_CLIENT_SECRETS': 'client_secrets.json',
# 'OIDC_ID_TOKEN_COOKIE_SECURE': False,
# 'OIDC_REQUIRE_VERIFIED_EMAIL': False,
# 'OIDC_VALID_ISSUERS': ['https://sso.santantoni.duckdns.org:8080/auth/realms/master'],
# 'OIDC_OPENID_REALM': 'https://sso.santantoni.duckdns.org//custom_callback',
# 'OVERWRITE_REDIRECT_URI': 'https://sso.santantoni.duckdns.org//custom_callback',
# })
# # 'OVERWRITE_REDIRECT_URI': 'https://sso.santantoni.duckdns.org//custom_callback',
# # 'OIDC_CALLBACK_ROUTE': '//custom_callback'
# oidc = OpenIDConnect(app)
''' OIDC TESTS '''
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"
@ -33,12 +30,12 @@ ram_users={
os.environ["ADMINAPP_USER"]: {
'id': os.environ["ADMINAPP_USER"],
'password': os.environ["ADMINAPP_PASSWORD"],
'role': 'admin'
'role': 'manager'
},
os.environ["KEYCLOAK_USER"]: {
'id': os.environ["KEYCLOAK_USER"],
'password': os.environ["KEYCLOAK_PASSWORD"],
'role': 'admin-keycloak',
'role': 'admin',
}
}

View File

@ -247,6 +247,7 @@ class Admin():
"username":u['username'],
"first": u.get('first_name',None),
"last": u.get('last_name',None),
"enabled": u['enabled'],
"email": u.get('email',''),
"groups": u['group'],
"roles": filter_roles_list(u['role'])}
@ -430,7 +431,7 @@ class Admin():
'username': u['username'].strip(),
'groups':user_groups,
'roles':[u['role'].strip()],
'password':diceware.get_passphrase(options=options)})
'password': self.get_dice_pwd()})
item+=1
ev.increment({'name':u['username'].split('@')[0]})
self.external['users']=users
@ -447,13 +448,19 @@ class Admin():
self.external['groups']=sysgroups
return True
def get_dice_pwd(self):
return diceware.get_passphrase(options=options)
def upload_json_ga(self,data):
groups=[]
log.warning('Processing uploaded groups...')
ev=Events('Processing uploaded groups',total=len(data['data']['groups']))
try:
ev=Events('Processing uploaded groups','Group:',total=len(data['data']['groups']))
except:
log.error(traceback.format_exc())
for g in data['data']['groups']:
try:
ev.increment({'name':g['name']})
ev.increment({'name':g['name'],'data':g})
groups.append({'provider':'external',
"id": g['id'],
"mailid": g['email'].split('@')[0],
@ -467,10 +474,10 @@ class Admin():
users=[]
total=len(data['data']['users'])
item=1
ev=Events('Processing uploaded users',total=len(data['data']['users']))
ev=Events('Processing uploaded users','User:',total=len(data['data']['users']))
for u in data['data']['users']:
log.warning('Processing ('+str(item)+'/'+str(total)+') uploaded user: '+u['primaryEmail'].split('@')[0])
users.append({'provider':'external',
new_user={'provider':'external',
'id':u['id'],
'email': u['primaryEmail'],
'first': u['name']['givenName'],
@ -478,9 +485,10 @@ class Admin():
'username': u['primaryEmail'].split('@')[0],
'groups':[u['orgUnitPath']], ## WARNING: Removing the first
'roles':[],
'password': diceware.get_passphrase(options=options)})
'password': diceware.get_passphrase(options=options)}
users.append(new_user)
item+=1
ev.increment({'name':u['primaryEmail'].split('@')[0]})
ev.increment({'name':u['primaryEmail'].split('@')[0],'data':new_user})
self.external['users']=users
## Add groups to users (now they only have their orgUnitPath)
@ -495,14 +503,13 @@ class Admin():
log.warning('Starting sync to keycloak')
self.sync_to_keycloak()
### Now we only sycn external to keycloak and then they can be updated to others with UI buttons
# log.warning('Starting sync to moodle')
# self.sync_to_moodle()
# log.warning('Starting sync to nextcloud')
# self.sync_to_nextcloud()
# log.warning('All syncs finished')
log.warning('Starting sync to moodle')
self.sync_to_moodle()
log.warning('Starting sync to nextcloud')
self.sync_to_nextcloud()
log.warning('All syncs finished')
def sync_to_keycloak(self): ### This one works from the external, moodle and nextcloud from the internal
groups=[]
for u in self.external['users']:
groups=groups+u['groups']
@ -510,7 +517,7 @@ class Admin():
total=len(groups)
i=0
ev=Events('Syncing import groups to keycloak',total=len(groups))
ev=Events('Syncing import groups to keycloak','Adding group:',total=len(groups))
for g in groups:
i=i+1
log.warning(' KEYCLOAK GROUPS: Adding group ('+str(i)+'/'+str(total)+'): '+g)
@ -519,12 +526,12 @@ class Admin():
total=len(self.external['users'])
index=0
ev=Events('Syncing import users to keycloak',total=len(self.external['users']))
ev=Events('Syncing import users to keycloak','Adding user:',total=len(self.external['users']))
for u in self.external['users']:
index=index+1
# Add user
log.warning(' KEYCLOAK USERS: Adding user ('+str(index)+'/'+str(total)+'): '+u['username'])
ev.increment({'name':u['username']})
ev.increment({'name':u['username'],'data':u})
uid=self.keycloak.add_user(u['username'],u['first'],u['last'],u['email'],u['password'])
# Add user to role and group rolename
@ -538,11 +545,10 @@ class Admin():
parts=g.split('/')
sub=''
if len(parts)==0:
log.warning(' KEYCLOAK USERS: Skip assign user '+u['username']+' to any group as des not have one')
log.warning(' KEYCLOAK USERS: Skip assign user '+u['username']+' to any group as does not have one')
continue # NO GROUP
for i in range(1,len(parts)):
sub=sub+'/'+parts[i]
if sub=='/': continue # User with no path
log.warning(' KEYCLOAK USERS: Assign user '+u['username']+' to group '+ str(sub))
gid=self.keycloak.get_group_by_path(path=sub)['id']
@ -588,7 +594,6 @@ class Admin():
if u['first'] == '': u['first']=' '
if u['last'] == '': u['last']=' '
try:
# pprint(u)
pprint(self.moodle.create_user(u['email'],u['username'],'1Random 1String',u['first'],u['last'])[0])
except:
log.error(' -->> Error creating on moodle the user: '+u['username'])
@ -604,7 +609,6 @@ class Admin():
for g in u['keycloak_groups']:
parts=g.split('/')
subpath=''
# pprint(parts)
for i in range(1,len(parts)):
if parts[i] in ['admin','manager','teacher','student']:
subpath=parts[i]
@ -663,9 +667,24 @@ class Admin():
except:
log.error(traceback.format_exc())
def delete_keycloak_user(self,userid):
user=[u for u in self.internal['users'] if u['id']==userid]
if len(user) and user[0]['keycloak']:
user=user[0]
keycloak_id=user['id']
else:
return False
log.warning('Removing keycloak user: '+user['username'])
try:
self.keycloak.delete_user(keycloak_id)
except:
log.error(traceback.format_exc())
log.warning('Could not remove users: '+user['username'])
def delete_keycloak_users(self):
total=len(self.internal['users'])
i=0
ev=Events('Deleting users from keycloak','Deleting user:',total=len(self.internal['users']))
for u in self.internal['users']:
i=i+1
if not u['keycloak']: continue
@ -673,29 +692,53 @@ class Admin():
if ['admin'] in u['roles']: continue
log.info(' KEYCLOAK USERS: Removing user ('+str(i)+'/'+str(total)+'): '+u['username'])
try:
ev.increment({'name':u['username'],'data':u})
self.keycloak.delete_user(u['id'])
app.socketio.emit('update',
json.dumps({'status':True,'item':'user','action':'delete','itemdata':u}),
namespace='/isard-sso-admin/sio',
room='admin')
except:
log.warning(' KEYCLOAK USERS: Could not remove user: '+u['username'] +'. Probably already not exists.')
def delete_nextcloud_user(self,userid):
user=[u for u in self.internal['users'] if u['id']==userid]
if len(user) and user[0]['nextcloud']:
user=user[0]
nextcloud_id=user['nextcloud_id']
else:
return False
log.warning('Removing nextcloud user: '+user['username'])
try:
self.nextcloud.delete_user(nextcloud_id)
except:
log.error(traceback.format_exc())
log.warning('Could not remove users: '+user['username'])
def delete_nextcloud_users(self):
ev=Events('Deleting users from nextcloud',total=len(self.internal['users']))
for u in self.internal['users']:
if u['nextcloud'] and not u['keycloak']:
if u['roles'] and 'admin' in u['roles']: continue
log.info('Removing nextcloud user: '+u['username'])
try:
self.nextcloud.delete_user(u['nextcloud_id'])
app.socketio.emit('update',
json.dumps({'status':True,'item':'user','action':'delete','itemdata':u}),
namespace='/isard-sso-admin/sio',
room='admin')
ev.increment({'name':u['username']})
self.nextcloud.delete_user(u['nextcloud_id'])
except:
log.error(traceback.format_exc())
log.warning('Could not remove user: '+u['username'])
def delete_moodle_user(self,userid):
user=[u for u in self.internal['users'] if u['id']==userid]
if len(user) and user[0]['moodle']:
user=user[0]
moodle_id=user['moodle_id']
else:
return False
log.warning('Removing moodle user: '+user['username'])
try:
self.moodle.delete_users([moodle_id])
except:
log.error(traceback.format_exc())
log.warning('Could not remove users: '+user['username'])
def delete_moodle_users(self):
userids=[]
usernames=[]
@ -709,13 +752,14 @@ class Admin():
self.moodle.delete_users(userids)
app.socketio.emit('update',
json.dumps({'status':True,'item':'user','action':'delete','itemdata':u}),
namespace='/isard-sso-admin/sio',
namespace='//sio',
room='admin')
except:
log.error(traceback.format_exc())
log.warning('Could not remove users: '+','.join(usernames))
def delete_keycloak_groups(self):
for g in self.internal['groups']:
if not g['keycloak']: continue
@ -733,4 +777,18 @@ class Admin():
for externaluser in self.external['users']:
if externaluser['id'] == newuserid:
externaluser['roles']=[data['action']]
return True
return True
def user_update_password(self,userid,password,temporary):
return self.keycloak.update_user_pwd(userid,password,temporary)
def delete_user(self,userid):
log.warning('deleting user moodle, nextcloud keycloak')
self.delete_moodle_user(userid)
self.delete_nextcloud_user(userid)
self.delete_keycloak_user(userid)
self.resync_data()
return True
def get_user(self,userid):
return [u for u in self.internal['users'] if u['id']==userid][0]

View File

@ -52,4 +52,4 @@ class Avatars():
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'] not in self.minio_get_objects()]
return [u for u in users if u['id'] and u['id'] not in self.minio_get_objects()]

View File

@ -23,51 +23,80 @@ class Events():
self.create()
def create(self):
log.info('START '+self.eid+': '+self.text)
app.socketio.emit('notify-create',
json.dumps({'id':self.eid,
'title':self.title,
'text':self.text}),
namespace='/isard-sso-admin/sio',
namespace='/sio',
room='admin')
sleep(0.1)
sleep(0.001)
def __del__(self):
log.info('END '+self.eid+': '+self.text)
app.socketio.emit('notify-destroy',
json.dumps({'id':self.eid}),
namespace='/isard-sso-admin/sio',
namespace='/sio',
room='admin')
sleep(0.1)
sleep(0.001)
def update_text(self,text):
self.text=text
app.socketio.emit('notify-update',
json.dumps({'id':self.eid,
'text':self.text,}),
namespace='/isard-sso-admin/sio',
namespace='/sio',
room='admin')
sleep(0.1)
sleep(0.001)
def increment(self,data={}):
def append_text(self,text):
self.text=self.text+'<br>'+text
app.socketio.emit('notify-update',
json.dumps({'id':self.eid,
'text':self.text,}),
namespace='/sio',
room='admin')
sleep(0.001)
def increment(self,data={'name':'','data':[]}):
self.item+=1
log.info('INCREMENT '+self.eid+': '+self.text)
app.socketio.emit('notify-update',
json.dumps({'id':self.eid,
'text': '['+str(self.item)+'/'+str(self.total)+'] ',
'title':self.title,
'text': '['+str(self.item)+'/'+str(self.total)+'] '+self.text+' '+data['name'],
'item':self.item,
'total':self.total,
'data':data}),
namespace='/isard-sso-admin/sio',
namespace='/sio',
room='admin')
sleep(0.1)
sleep(0.0001)
def decrement(self,data={}):
def decrement(self,data={'name':'','data':[]}):
self.item-=1
log.info('DECREMENT '+self.eid+': '+self.text)
app.socketio.emit('notify-update',
json.dumps({'id':self.eid,
'text':'['+str(self.item)+'/'+str(self.total)+'] ',
'title':self.title,
'text': '['+str(self.item)+'/'+str(self.total)+'] '+self.text+' '+data['name'],
'item':self.item,
'total':self.total,
'data':data}),
namespace='/isard-sso-admin/sio',
namespace='/sio',
room='admin')
sleep(0.1)
sleep(0.001)
def reload(self):
app.socketio.emit('reload',
json.dumps({}),
namespace='/sio',
room='admin')
sleep(0.0001)
def table(self,event,table,data={}):
# refresh, add, delete, update
app.socketio.emit('table_'+event,
json.dumps({'table':table,'data':data}),
namespace='/sio',
room='admin')
sleep(0.0001)

View File

@ -60,7 +60,7 @@ class KeycloakClient():
# self.add_role('superman')
# pprint(self.get_roles())
## USERS
''' USERS '''
def get_user_id(self,username):
self.connect()
@ -71,7 +71,7 @@ class KeycloakClient():
return self.keycloak_admin.get_users({})
def get_users_with_groups_and_roles(self):
q = """select u.id, u.username, u.email, u.first_name, u.last_name, u.realm_id, ua.value as quota
q = """select u.id, u.username, u.email, u.first_name, u.last_name, u.realm_id, u.enabled, ua.value as quota
,json_agg(g."name") as group, json_agg(g_parent."name") as group_parent1, json_agg(g_parent2."name") as group_parent2
,json_agg(r.name) as role
from user_entity as u
@ -82,7 +82,7 @@ class KeycloakClient():
left join keycloak_group as g_parent2 on g_parent.parent_group = g_parent2.id
left join user_role_mapping as rm on rm.user_id = u.id
left join keycloak_role as r on r.id = rm.role_id
group by u.id,u.username,u.email,u.first_name,u.last_name, u.realm_id, ua.value
group by u.id,u.username,u.email,u.first_name,u.last_name, u.realm_id, u.enabled, ua.value
order by u.username"""
(headers,users)=self.keycloak_pg.select_with_headers(q)
@ -103,6 +103,7 @@ class KeycloakClient():
def getparent(self,group_id, data):
# Recursively get full path from any group_id in the tree
path = ""
for item in data:
if group_id == item[0]:
@ -111,11 +112,15 @@ class KeycloakClient():
return path
def get_group_path(self,group_id):
# Get full path using getparent recursive func
# RETURNS: String with full path
q = """SELECT * FROM keycloak_group"""
groups=self.keycloak_pg.select(q)
return self.getparent(group_id,groups)
def get_user_groups_paths(self,user_id):
# Get full paths for user grups
# RETURNS list of paths
q = """SELECT group_id FROM user_group_membership WHERE user_id = '%s'""" % (user_id)
user_group_ids=self.keycloak_pg.select(q)
@ -124,7 +129,7 @@ class KeycloakClient():
paths.append(self.get_group_path(g[0]))
return paths
## Too slow
## Too slow. Used the direct postgres
# def get_users_with_groups_and_roles(self):
# self.connect()
# users=self.keycloak_admin.get_users({})
@ -134,7 +139,7 @@ class KeycloakClient():
# return users
def add_user(self,username,first,last,email,password,group=False,temporary=True):
# Returns user id
# RETURNS string with keycloak user id (the main id in this app)
self.connect()
username=username.lower()
try:
@ -159,12 +164,13 @@ class KeycloakClient():
self.keycloak_admin.group_user_add(uid,gid)
return uid
def update_user_pwd(self,user_id='61092e24-cd67-4b50-baf9-b60e01f12bff',payload={},temporary=True):
def update_user_pwd(self,user_id,password,temporary=True):
# Updates
payload={"credentials":[{"type":"password",
"value":'pepito',
"value":password,
"temporary":temporary}]}
self.connect()
self.keycloak_admin.update_user( user_id, payload)
return self.keycloak_admin.update_user( user_id, payload)
def remove_user_group(self,user_id,group_id):
self.connect()
@ -219,7 +225,6 @@ class KeycloakClient():
def add_group(self,name,parent=None,skip_exists=False):
self.connect()
print('parent_path: '+str(parent))
if parent is not None: parent=self.get_group_by_path(parent)['id']
return self.keycloak_admin.create_group({"name":name}, parent=parent)
@ -286,11 +291,11 @@ class KeycloakClient():
else:
thepath=parent_path+'/'+parts[i]
if thepath=='/':
print('Not adding the user '+username+' to any group as does not have any...')
log.warning('Not adding the user '+username+' to any group as does not have any...')
continue
gid=self.get_group_by_path(path=thepath)['id']
print('Adding '+username+' with uuid: '+uid+' to group '+g+' with uuid: '+gid)
log.warning('Adding '+username+' with uuid: '+uid+' to group '+g+' with uuid: '+gid)
self.keycloak_admin.group_user_add(uid,gid)
@ -360,4 +365,4 @@ class KeycloakClient():
def add_client(self,client):
self.connect()
return self.keycloak_admin.create_client(client)
return self.keycloak_admin.create_client(client)

View File

@ -88,15 +88,16 @@ class Moodle():
def get_users_with_groups_and_roles(self):
q = """select u.id as id, username, firstname as first, lastname as last, email, json_agg(h.name) as groups, json_agg(r.shortname) as roles
from mdl_user as u
LEFT JOIN mdl_cohort_members AS hm on hm.id = u.id
LEFT JOIN mdl_cohort_members AS hm on hm.userid = u.id
left join mdl_cohort AS h ON h.id = hm.cohortid
left join mdl_role_assignments AS ra ON ra.id = u.id
left join mdl_role as r on r.id = ra.roleid
where u.deleted = 0
group by u.id , username, first, last, email"""
(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)
pprint(list_dict_users)
return list_dict_users
## NOT USED. Too slow

View File

@ -1,19 +0,0 @@
#Add this app service
registres mdl_external_services
registres mdl_external_services_functions
registres mdl_external_services_users
# SAML
mdl_auth_saml2_idps
/opt/digitaldemocratic/data/moodle/saml2# ls
0f635d0e0f3874fff8b581c132e6c7a7.idp.xml moodle.santantoni.duckdns.org.crt moodle.santantoni.duckdns.org.pem
echo -n xml | md5sum
0f635d0e0f3874fff8b581c132e6c7a7
SELECT * FROM "mdl_config" WHERE ("name" LIKE '%saml%' OR "value" LIKE '%saml%') LIMIT 50 (0.001 s) Edita
Modify id name value
edita 3 auth email,saml2
privatekey_pass = mdl_config siteidentifier

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

View File

View File

@ -20,7 +20,7 @@ $(document).ready(function() {
// console.log(ids)
$.ajax({
type: "PUT",
url:"/isard-sso-admin/external",
url:"/api/external",
data: JSON.stringify(ids),
success: function(data)
{
@ -58,7 +58,7 @@ $(document).ready(function() {
}
$.ajax({
type: "POST",
url:"/isard-sso-admin/external",
url:"/api/external",
data: JSON.stringify(formdata),
success: function(data)
{
@ -111,7 +111,7 @@ $(document).ready(function() {
}).get().on('pnotify.confirm', function() {
$.ajax({
type: "PUT",
url:"/isard-sso-admin/external/roles",
url:"/api/external/roles",
data: JSON.stringify({'ids':ids,'action':action}),
success: function(data)
{
@ -132,7 +132,7 @@ $(document).ready(function() {
//DataTable Main renderer
var users_table = $('#users').DataTable({
"ajax": {
"url": "/isard-sso-admin/external_users_list",
"url": "/api/external/users",
"dataSrc": ""
},
"language": {
@ -171,7 +171,7 @@ $(document).ready(function() {
var groups_table = $('#groups').DataTable({
"ajax": {
"url": "/isard-sso-admin/external_groups_list",
"url": "/api/external/groups",
"dataSrc": ""
},
"language": {

View File

@ -8,7 +8,7 @@ $(document).ready(function() {
$('.btn-global-resync').on('click', function () {
$.ajax({
type: "GET",
url:"/isard-sso-admin/resync",
url:"api/resync",
success: function(data)
{
table.ajax.reload();
@ -39,7 +39,7 @@ $(document).ready(function() {
console.log(formdata)
// $.ajax({
// type: "POST",
// "url": "/isard-sso-admin/groups_list",
// "url": "/groups_list",
// success: function(data)
// {
// console.log('SUCCESS')
@ -55,7 +55,7 @@ $(document).ready(function() {
$('.btn-delete_keycloak').on('click', function () {
$.ajax({
type: "DELETE",
url:"/isard-sso-admin/groups/keycloak",
url:"/api/groups/keycloak",
success: function(data)
{
console.log('SUCCESS')
@ -73,7 +73,7 @@ $(document).ready(function() {
//DataTable Main renderer
var table = $('#groups').DataTable({
"ajax": {
"url": "/isard-sso-admin/groups_list",
"url": "/api/groups",
"dataSrc": ""
},
"language": {

View File

@ -8,7 +8,7 @@ $(document).ready(function() {
$('.btn-global-resync').on('click', function () {
$.ajax({
type: "GET",
url:"/isard-sso-admin/resync",
url:"/api/resync",
success: function(data)
{
table.ajax.reload();
@ -35,7 +35,7 @@ $(document).ready(function() {
//DataTable Main renderer
var table = $('#roles').DataTable({
"ajax": {
"url": "/isard-sso-admin/roles_list",
"url": "/api/roles",
"dataSrc": ""
},
"language": {

View File

@ -1,8 +1,8 @@
notice={}
$lost=0;
socket = io.connect(location.protocol+'//' + document.domain +'/isard-sso-admin/sio');
console.log(location.protocol+'//' + document.domain +'/isard-sso-admin/sio')
socket = io.connect(location.protocol+'//' + document.domain +'/sio');
console.log(location.protocol+'//' + document.domain +'/sio')
socket.on('connect', function() {
if($lost){location.reload();}
console.log('Listening status socket');
@ -32,6 +32,13 @@ socket.on('notify-destroy', function(data) {
socket.on('notify-update', function(data) {
var data = JSON.parse(data);
if(!( data.id in notice)){
notice[data.id] = new PNotify({
title: data.title,
text: data.text,
hide: false
});
}
// console.log(data.text)
notice[data.id].update({
text: data.text

View File

@ -0,0 +1,443 @@
$(document).on('shown.bs.modal', '#modalAddDesktop', function () {
modal_add_desktops.columns.adjust().draw();
});
$(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",
success: function(data)
{
console.log('ROLES')
console.log(data)
data.forEach(element => {
$(".role-moodle-select, .role-nextcloud-select, .role-keycloak-select").append(
'<option value=' + element.id + '>' + element.name + '</option>'
)
})
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
$('.btn-global-resync').on('click', function () {
$.ajax({
type: "GET",
url:"/api/resync",
success: function(data)
{
console.log('Reloaded')
table.ajax.reload();
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
// groups_table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
});
// Open new user modal
$('.btn-new-user').on('click', function () {
$('#modalAddUser').modal({
backdrop: 'static',
keyboard: false
}).modal('show');
});
// Send new user form
$('#modalAddUser #send').on('click', function () {
var form = $('#modalAddUserForm');
formdata = form.serializeObject()
console.log('NEW USER')
console.log(formdata)
// $.ajax({
// type: "POST",
// "url": "/groups_list",
// success: function(data)
// {
// console.log('SUCCESS')
// // $("#modalAddUser").modal('hide');
// },
// error: function(data)
// {
// alert('Something went wrong on our side...')
// }
// });
});
$('.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": {
"url": "/api/users",
"dataSrc": ""
},
"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>"
},
"rowId": "id",
"deferRender": true,
"columns": [
{
"className": 'details-control',
"orderable": false,
"data": null,
"width": "10px",
"defaultContent": '<button class="btn btn-xs btn-info" type="button" data-placement="top" ><i class="fa fa-plus"></i></button>'
},
{ "data": "id", "width": "10px" },
{ "data": "username", "width": "10px"},
{ "data": "first", "width": "10px"},
{ "data": "last", "width": "10px"},
{ "data": "email", "width": "10px"},
{ "data": "keycloak", "width": "10px" },
{ "data": "keycloak_groups", "width": "10px" },
{ "data": "roles", "width": "10px" },
{ "data": "moodle", "width": "10px" },
{ "data": "moodle_groups", "width": "10px" },
{ "data": "nextcloud", "width": "10px" },
{ "data": "nextcloud_groups", "width": "10px" },
],
"order": [[4, 'asc']],
"columnDefs": [ {
"targets": 1,
"render": function ( data, type, full, meta ) {
return '<object data="/static/img/missing.jpg" type="image/jpg" width="25" height="25"><img src="/avatar/'+full.id+'" title="'+full.id+'" width="25" height="25"></object>'
}},
{
"targets": 6,
"render": function ( data, type, full, meta ) {
if(full.keycloak){
return '<i class="fa fa-check" style="color:lightgreen"></i>'
}else{
return '<i class="fa fa-close" style="color:darkred"></i>'
};
}},
{
"targets": 7,
"render": function ( data, type, full, meta ) {
return "<li>" + full.keycloak_groups.join("</li><li>") + "</li>"
}},
{
"targets": 9,
"render": function ( data, type, full, meta ) {
if(full.moodle){
return '<i class="fa fa-check" style="color:lightgreen"></i>'
}else{
return '<i class="fa fa-close" style="color:darkred"></i>'
};
}},
{
"targets": 10,
"render": function ( data, type, full, meta ) {
return "<li>" + full.moodle_groups.join("</li><li>") + "</li>"
}},
{
"targets": 11,
"render": function ( data, type, full, meta ) {
if(full.nextcloud){
return '<i class="fa fa-check" style="color:lightgreen"></i>'
}else{
return '<i class="fa fa-close" style="color:darkred"></i>'
};
}},
{
"targets": 12,
"render": function ( data, type, full, meta ) {
return "<li>" + full.nextcloud_groups.join("</li><li>") + "</li>"
}},
]
} );
$template = $(".template-detail-users");
$('#users').find('tbody').on('click', 'td.details-control', function () {
var tr = $(this).closest('tr');
var row = table.row( tr );
if ( row.child.isShown() ) {
// This row is already open - close it
row.child.hide();
tr.removeClass('shown');
}
else {
// Close other rows
if ( table.row( '.shown' ).length ) {
$('.details-control', table.row( '.shown' ).node()).click();
}
// Open this row
row.child( addUserDetailPannel(row.data()) ).show();
tr.addClass('shown');
actionsUserDetail()
}
} );
function addUserDetailPannel ( d ) {
$newPanel = $template.clone();
$newPanel.html(function(i, oldHtml){
return oldHtml.replace(/d.id/g, d.id).replace(/d.username/g, d.username);
});
return $newPanel
}
function actionsUserDetail(){
$('.btn-passwd').on('click', function () {
var closest=$(this).closest("div").parent();
var pk=closest.attr("data-pk");
$("#modalPasswdUserForm")[0].reset();
$('#modalPasswdUser').modal({
backdrop: 'static',
keyboard: false
}).modal('show');
$('#modalPasswdUserForm #id').val(pk);
});
$("#modalPasswdUser #send").on('click', function(e){
var form = $('#modalPasswdUserForm');
form.parsley().validate();
if (form.parsley().isValid()){
data=$('#modalPasswdUserForm').serializeObject();
data['id']=$('#modalPasswdUserForm #id').val();
new PNotify({
title: 'Confirmation Needed',
text: "Are you sure you want to update password for the user "+ username+"?",
hide: false,
opacity: 0.9,
confirm: {
confirm: true
},
buttons: {
closer: false,
sticker: false
},
history: {
history: false
},
addclass: 'pnotify-center'
}).get().on('pnotify.confirm', function() {
console.log('Updating user password...')
$.ajax({
type: "PUT",
url:"/api/user" + id,
success: function(data)
{
$(div_id + ' #id').val(data.id);
$(div_id + ' #username').val(data.username);
$(div_id + ' #email').val(data.email);
$(div_id + ' #firstname').val(data.firstname);
$(div_id + ' #lastname').val(data.lastname);
$(div_id + ' .groups-select').val(data.groups);
$(div_id + ' .role-moodle-select').val(data.roles);
$(div_id + ' .role-nextcloud-select').val(data.roles);
$(div_id + ' .role-keycloak-select').val(data.roles);
$('.groups-select, .role-moodle-select, .role-nextcloud-select, .role-keycloak-select').trigger('change');
}
});
}).on('pnotify.cancel', function() {
});
}
});
$('.btn-edit').on('click', function () {
var closest=$(this).closest("div").parent();
var pk=closest.attr("data-pk");
$("#modalEditUserForm")[0].reset();
$('#modalEditUser').modal({
backdrop: 'static',
keyboard: false
}).modal('show');
setUserDefault('#modalEditUser', pk);
$('#modalEdit').parsley();
});
$("#modalEditUser #send").on('click', function(e){
var form = $('#modalEditUserForm');
form.parsley().validate();
if (form.parsley().isValid()){
data=$('#modalEditUserForm').serializeObject();
data['id']=$('#modalEditUserForm #id').val();
console.log('Editing user...')
console.log(data)
}
});
$('.btn-delete').on('click', function () {
var closest=$(this).closest("div").parent();
var pk=closest.attr("data-pk");
var username=closest.attr("data-username");
console.log(username)
new PNotify({
title: 'Confirmation Needed',
text: "Are you sure you want to delete the user: "+ username+"?",
hide: false,
opacity: 0.9,
confirm: {
confirm: true
},
buttons: {
closer: false,
sticker: false
},
history: {
history: false
},
addclass: 'pnotify-center'
}).get().on('pnotify.confirm', function() {
console.log('Deleting user...')
}).on('pnotify.cancel', function() {
});
});
}
function setUserDefault(div_id, user_id) {
// $.ajax({
// type: "GET",
// url:"/api/user/" + id,
// success: function(data)
// {
// $(div_id + ' #id').val(data.id);
// $(div_id + ' #username').val(data.username);
// $(div_id + ' #email').val(data.email);
// $(div_id + ' #firstname').val(data.firstname);
// $(div_id + ' #lastname').val(data.lastname);
// $(div_id + ' .groups-select').val(data.groups);
// $(div_id + ' .role-moodle-select').val(data.roles);
// $(div_id + ' .role-nextcloud-select').val(data.roles);
// $(div_id + ' .role-keycloak-select').val(data.roles);
// $('.groups-select, .role-moodle-select, .role-nextcloud-select, .role-keycloak-select').trigger('change');
// }
// });
// MOCK
$(div_id + ' #id').val('b57c8d3f-ee08-4a1d-9873-f40c082b9c69');
$(div_id + ' #user-avatar').attr('src', '/static/img/usera.jpg');
$(div_id + ' #username').val('yedcaqwvt');
$(div_id + ' #email').val('yedcaqwvt@institutmariaespinalt.cat');
$(div_id + ' #firstname').val('Ymisno');
$(div_id + ' #lastname').val('Edcaqwvt tavnuoes');
$(div_id + ' .groups-select').val(['student', 'manager']);
$(div_id + ' .role-moodle-select').val('51cc1a95-94b7-48eb-aebb-1eba6745e09f');
$(div_id + ' .role-nextcloud-select').val('1e21ec95-b8c7-43b8-baad-1a31ad33f388');
$(div_id + ' .role-keycloak-select').val('13da53d5-c50b-42d9-8fbf-84f2ed7cbf9e');
$('.groups-select, .role-moodle-select, .role-nextcloud-select, .role-keycloak-select').trigger('change');
}
});

View File

@ -7,18 +7,18 @@ $(document).ready(function() {
$.ajax({
type: "GET",
"url": "/isard-sso-admin/groups_list",
"url": "/api/groups",
success: function(data)
{
data.forEach(element => {
var groupOrigins = [];
['keycloak', 'moodle', 'nextcloud'].forEach(o => {
['keycloak'].forEach(o => {
if (element[o]) {
groupOrigins.push(o)
}
})
$(".groups-select").append(
'<option value=' + element.path + '>' + element.name + ' (' + groupOrigins.join(',') + ') </option>'
'<option value=' + element.path + '>' + element.name + '</option>'
)
});
$('.groups-select').select2();
@ -29,13 +29,35 @@ $(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": "/isard-sso-admin/roles_list",
"url": "/api/roles",
success: function(data)
{
console.log('ROLES')
console.log(data)
data.forEach(element => {
$(".role-moodle-select, .role-nextcloud-select, .role-keycloak-select").append(
'<option value=' + element.id + '>' + element.name + '</option>'
@ -51,10 +73,9 @@ $(document).ready(function() {
$('.btn-global-resync').on('click', function () {
$.ajax({
type: "GET",
url:"/isard-sso-admin/resync",
url:"/api/resync",
success: function(data)
{
console.log('Reloaded')
table.ajax.reload();
// $("#modalImport").modal('hide');
// users_table.ajax.reload();
@ -83,7 +104,7 @@ $(document).ready(function() {
console.log(formdata)
// $.ajax({
// type: "POST",
// "url": "/isard-sso-admin/groups_list",
// "url": "/groups_list",
// success: function(data)
// {
// console.log('SUCCESS')
@ -99,7 +120,7 @@ $(document).ready(function() {
$('.btn-delete_keycloak').on('click', function () {
$.ajax({
type: "DELETE",
url:"/isard-sso-admin/users/keycloak",
url:"/api/users/keycloak",
success: function(data)
{
console.log('SUCCESS')
@ -117,7 +138,7 @@ $(document).ready(function() {
$('.btn-delete_nextcloud').on('click', function () {
$.ajax({
type: "DELETE",
url:"/isard-sso-admin/users/nextcloud",
url:"/api/users/nextcloud",
success: function(data)
{
console.log('SUCCESS')
@ -135,7 +156,7 @@ $(document).ready(function() {
$('.btn-delete_moodle').on('click', function () {
$.ajax({
type: "DELETE",
url:"/isard-sso-admin/users/moodle",
url:"/api/users/moodle",
success: function(data)
{
console.log('SUCCESS')
@ -152,7 +173,7 @@ $(document).ready(function() {
$('.btn-sync_to_moodle').on('click', function () {
$.ajax({
type: "POST",
url:"/isard-sso-admin/users/moodle",
url:"/api/users/moodle",
success: function(data)
{
console.log('SUCCESS')
@ -170,7 +191,7 @@ $(document).ready(function() {
$('.btn-sync_to_nextcloud').on('click', function () {
$.ajax({
type: "POST",
url:"/isard-sso-admin/users/nextcloud",
url:"/api/users/nextcloud",
success: function(data)
{
console.log('SUCCESS')
@ -188,84 +209,68 @@ $(document).ready(function() {
//DataTable Main renderer
var table = $('#users').DataTable({
"ajax": {
"url": "/isard-sso-admin/users_list",
"url": "/api/users",
"dataSrc": ""
},
"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>"
},
},
"rowId": "id",
"deferRender": true,
"columns": [
{
"className": 'details-control',
"orderable": false,
"data": null,
"width": "10px",
"defaultContent": '<button class="btn btn-xs btn-info" type="button" data-placement="top" ><i class="fa fa-plus"></i></button>'
},
{"data": null, "defaultContent":'',"width": "1px"},
// {
// "className": 'details-control',
// "orderable": false,
// "data": null,
// "width": "10px",
// "defaultContent": '<button class="btn btn-xs btn-info" type="button" data-placement="top" ><i class="fa fa-plus"></i></button>'
// },
{ "data": "id", "width": "10px" },
{ "data": "username", "width": "10px"},
{ "data": "enabled", "width": "10px" },
{ "data": "username", "width": "10px"},
{
"className": 'actions-control',
"orderable": false,
"data": null,
"width": "80px",
"defaultContent": '<button id="btn-edit" class="btn btn-xs" type="button" data-placement="top" ><i class="fa fa-pencil" style="color:darkblue"></i></button> \
<button id="btn-delete" class="btn btn-xs" type="button" data-placement="top" ><i class="fa fa-times" style="color:darkred"></i></button> \
<button id="btn-password" class="btn btn-xs" type="button" data-placement="top" ><i class="fa fa-lock" style="color:orange"></i></button>'
},
{ "data": "first", "width": "10px"},
{ "data": "last", "width": "10px"},
{ "data": "last", "width": "200px"},
{ "data": "email", "width": "10px"},
{ "data": "keycloak", "width": "10px" },
{ "data": "keycloak_groups", "width": "10px" },
{ "data": "roles", "width": "10px" },
{ "data": "moodle", "width": "10px" },
{ "data": "moodle_groups", "width": "10px" },
{ "data": "nextcloud", "width": "10px" },
{ "data": "nextcloud_groups", "width": "10px" },
],
"order": [[4, 'asc']],
"order": [[6, 'asc']],
"columnDefs": [ {
"targets": 1,
"render": function ( data, type, full, meta ) {
return '<img src="/isard-sso-admin/avatars/'+full.id+'" title="'+full.id+'" width="25" height="25"></object>'
// 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">'
}},
{
"targets": 6,
"targets": 2,
"render": function ( data, type, full, meta ) {
if(full.keycloak){
if(full.enabled){
return '<i class="fa fa-check" style="color:lightgreen"></i>'
}else{
return '<i class="fa fa-close" style="color:darkred"></i>'
};
}},
{
"targets": 7,
"targets": 3,
"render": function ( data, type, full, meta ) {
return '<b>'+full.username+'</b>'
}},
{
"targets": 8,
"render": function ( data, type, full, meta ) {
return "<li>" + full.keycloak_groups.join("</li><li>") + "</li>"
}},
{
"targets": 9,
"render": function ( data, type, full, meta ) {
if(full.moodle){
return '<i class="fa fa-check" style="color:lightgreen"></i>'
}else{
return '<i class="fa fa-close" style="color:darkred"></i>'
};
}},
{
"targets": 10,
"render": function ( data, type, full, meta ) {
return "<li>" + full.moodle_groups.join("</li><li>") + "</li>"
}},
{
"targets": 11,
"render": function ( data, type, full, meta ) {
if(full.nextcloud){
return '<i class="fa fa-check" style="color:lightgreen"></i>'
}else{
return '<i class="fa fa-close" style="color:darkred"></i>'
};
}},
{
"targets": 12,
"render": function ( data, type, full, meta ) {
return "<li>" + full.nextcloud_groups.join("</li><li>") + "</li>"
}},
]
} );
@ -292,6 +297,117 @@ $(document).ready(function() {
}
} );
$('#users').find(' tbody').on( 'click', 'button', function () {
var data = table.row( $(this).parents('tr') ).data();
// var closest=$(this).closest("div").parent();
// var pk=closest.attr("data-pk");
// console.log(pk)
switch($(this).attr('id')){
case 'btn-edit':
$("#modalEditUserForm")[0].reset();
$('#modalEditUser').modal({
backdrop: 'static',
keyboard: false
}).modal('show');
$('#modalEditUser #user-avatar').attr("src","/avatar/"+data.id)
setUserDefault('#modalEditUser', data.id);
$('#modalEdit').parsley();
break;
case 'btn-delete':
new PNotify({
title: 'Confirmation Needed',
text: "Are you sure you want to delete user: "+data['username']+"?",
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/user/"+data.id,
success: function(data)
{
table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
}).on('pnotify.cancel', function() {
});
break;
case 'btn-password':
$("#modalPasswdUserForm")[0].reset();
$('#modalPasswdUser').modal({
backdrop: 'static',
keyboard: false
}).modal('show');
$('#modalPasswdUserForm #id').val(data.id);
$.ajax({
type: "GET",
url:"/api/user_password",
success: function(data)
{
$('#modalPasswdUserForm #password').val(data);
},
error: function(data)
{
alert('Something went wrong on our side...')
}
});
break;
}
});
$("#modalPasswdUser #send").on('click', function(e){
var form = $('#modalPasswdUserForm');
form.parsley().validate();
if (form.parsley().isValid()){
formdata=$('#modalPasswdUserForm').serializeObject();
id=$('#modalPasswdUserForm #id').val();
$.ajax({
type: "PUT",
url:"/api/user//+" + id,
data: JSON.stringify(formdata),
success: function(data)
{
$("#modalPasswdUser").modal('hide');
table.ajax.reload();
// groups_table.ajax.reload();
},
error: function(data)
{
alert('Something went wrong on our side...')
}
// statusCode: {
// 404: function(data) {
// // {'error': 'description}. Not able to get responseJSON from received object
// alert('User not exists in system!')
// },
// 200: function() {
// console.log("Success");
// }
// },
// error: function(data)
// {
// alert('Something went wrong on our side...')
// }
});
}
});
function addUserDetailPannel ( d ) {
$newPanel = $template.clone();
$newPanel.html(function(i, oldHtml){
@ -302,39 +418,30 @@ $(document).ready(function() {
function actionsUserDetail(){
$('.btn-passwd').on('click', function () {
var closest=$(this).closest("div").parent();
var pk=closest.attr("data-pk");
$("#modalPasswdUserForm")[0].reset();
$('#modalPasswdUser').modal({
backdrop: 'static',
keyboard: false
}).modal('show');
$('#modalPasswdUserForm #id').val(pk);
});
// $('.btn-passwd').on('click', function () {
// var closest=$(this).closest("div").parent();
// var pk=closest.attr("data-pk");
// $("#modalPasswdUserForm")[0].reset();
// $('#modalPasswdUser').modal({
// backdrop: 'static',
// keyboard: false
// }).modal('show');
// $('#modalPasswdUserForm #id').val(pk);
// });
$("#modalPasswdUser #send").on('click', function(e){
var form = $('#modalPasswdUserForm');
form.parsley().validate();
if (form.parsley().isValid()){
data=$('#modalPasswdUserForm').serializeObject();
data['id']=$('#modalPasswdUserForm #id').val();
console.log('Editing user password...')
console.log(data)
}
});
$('.btn-edit').on('click', function () {
var closest=$(this).closest("div").parent();
var pk=closest.attr("data-pk");
$("#modalEditUserForm")[0].reset();
$('#modalEditUser').modal({
backdrop: 'static',
keyboard: false
}).modal('show');
setUserDefault('#modalEditUser', pk);
$('#modalEdit').parsley();
});
// $('.btn-edit').on('click', function () {
// var closest=$(this).closest("div").parent();
// var pk=closest.attr("data-pk");
// $("#modalEditUserForm")[0].reset();
// $('#modalEditUser').modal({
// backdrop: 'static',
// keyboard: false
// }).modal('show');
// setUserDefault('#modalEditUser', pk);
// $('#modalEdit').parsley();
// });
$("#modalEditUser #send").on('click', function(e){
var form = $('#modalEditUserForm');
@ -347,62 +454,64 @@ $(document).ready(function() {
}
});
$('.btn-delete').on('click', function () {
var closest=$(this).closest("div").parent();
var pk=closest.attr("data-pk");
var username=closest.attr("data-username");
console.log(username)
new PNotify({
title: 'Confirmation Needed',
text: "Are you sure you want to delete the user: "+ username+"?",
hide: false,
opacity: 0.9,
confirm: {
confirm: true
},
buttons: {
closer: false,
sticker: false
},
history: {
history: false
},
addclass: 'pnotify-center'
}).get().on('pnotify.confirm', function() {
console.log('Deleting user...')
}).on('pnotify.cancel', function() {
});
});
// $('.btn-delete').on('click', function () {
// var closest=$(this).closest("div").parent();
// var pk=closest.attr("data-pk");
// var username=closest.attr("data-username");
// console.log(username)
// new PNotify({
// title: 'Confirmation Needed',
// text: "Are you sure you want to delete the user: "+ username+"?",
// hide: false,
// opacity: 0.9,
// confirm: {
// confirm: true
// },
// buttons: {
// closer: false,
// sticker: false
// },
// history: {
// history: false
// },
// addclass: 'pnotify-center'
// }).get().on('pnotify.confirm', function() {
// console.log('Deleting user...')
// }).on('pnotify.cancel', function() {
// });
// });
}
function setUserDefault(div_id, user_id) {
// $.ajax({
// type: "GET",
// url:"/isard-sso-admin/user/" + id,
// success: function(data)
// {
// $(div_id + ' #id').val(data.id);
// $(div_id + ' #username').val(data.username);
// $(div_id + ' #email').val(data.email);
// $(div_id + ' #firstname').val(data.firstname);
// $(div_id + ' #lastname').val(data.lastname);
// $(div_id + ' .groups-select').val(data.groups);
// $(div_id + ' .role-moodle-select').val(data.roles);
// $(div_id + ' .role-nextcloud-select').val(data.roles);
// $(div_id + ' .role-keycloak-select').val(data.roles);
// $('.groups-select, .role-moodle-select, .role-nextcloud-select, .role-keycloak-select').trigger('change');
// }
// });
$.ajax({
type: "GET",
url:"/api/user/" + user_id,
success: function(data)
{
$(div_id + ' #id').val(data.id);
$(div_id + ' #username').val(data.username);
$(div_id + ' #email').val(data.email);
$(div_id + ' #firstname').val(data.first);
$(div_id + ' #lastname').val(data.last);
console.log(data.keycloak_groups)
$(div_id + ' .groups-select').val(data.keycloak_groups);
// $(div_id + ' .role-moodle-select').val(data.keycloak_roles);
// $(div_id + ' .role-nextcloud-select').val(data.roles);
$(div_id + ' .role-keycloak-select').val(data.keycloak_roles);
$('.groups-select, .role-keycloak-select').trigger('change');
// $('.groups-select, .role-moodle-select, .role-nextcloud-select, .role-keycloak-select').trigger('change');
}
});
// MOCK
$(div_id + ' #id').val('b57c8d3f-ee08-4a1d-9873-f40c082b9c69');
$(div_id + ' #user-avatar').attr('src', 'static/img/usera.jpg');
$(div_id + ' #username').val('yedcaqwvt');
$(div_id + ' #email').val('yedcaqwvt@institutmariaespinalt.cat');
$(div_id + ' #firstname').val('Ymisno');
$(div_id + ' #lastname').val('Edcaqwvt tavnuoes');
$(div_id + ' .groups-select').val(['student', 'manager']);
$(div_id + ' .role-moodle-select').val('51cc1a95-94b7-48eb-aebb-1eba6745e09f');
$(div_id + ' .role-nextcloud-select').val('1e21ec95-b8c7-43b8-baad-1a31ad33f388');
$(div_id + ' .role-keycloak-select').val('13da53d5-c50b-42d9-8fbf-84f2ed7cbf9e');
$('.groups-select, .role-moodle-select, .role-nextcloud-select, .role-keycloak-select').trigger('change');
// $(div_id + ' #id').val('b57c8d3f-ee08-4a1d-9873-f40c082b9c69');
// $(div_id + ' #user-avatar').attr('src', 'static/img/usera.jpg');
// $(div_id + ' #username').val('yedcaqwvt');
// $(div_id + ' #email').val('yedcaqwvt@institutmariaespinalt.cat');
// $(div_id + ' #firstname').val('Ymisno');
// $(div_id + ' #lastname').val('Edcaqwvt tavnuoes');
// $(div_id + ' .groups-select').val(['student', 'manager']);
// $(div_id + ' .role-moodle-select').val('51cc1a95-94b7-48eb-aebb-1eba6745e09f');
// $(div_id + ' .role-nextcloud-select').val('1e21ec95-b8c7-43b8-baad-1a31ad33f388');
// $(div_id + ' .role-keycloak-select').val('13da53d5-c50b-42d9-8fbf-84f2ed7cbf9e');
// $('.groups-select, .role-moodle-select, .role-nextcloud-select, .role-keycloak-select').trigger('change');
}
});

View File

@ -14,27 +14,27 @@
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />
<!-- Fancytree -->
<link href="/isard-sso-admin/static/vendor/fancytree/dist/skin-win8/ui.fancytree.css" rel="stylesheet">
<link href="/static/vendor/fancytree/dist/skin-win8/ui.fancytree.css" rel="stylesheet">
<!-- Bootstrap -->
<link href="/isard-sso-admin/vendors/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/vendors/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="/isard-sso-admin/vendors/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<link href="/vendors/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<!-- ion.rangeSlider -->
<link href="/isard-sso-admin/vendors/ion.rangeSlider/css/ion.rangeSlider.css" rel="stylesheet">
<link href="/isard-sso-admin/vendors/ion.rangeSlider/css/ion.rangeSlider.skinFlat.css" rel="stylesheet">
<link href="/vendors/ion.rangeSlider/css/ion.rangeSlider.css" rel="stylesheet">
<link href="/vendors/ion.rangeSlider/css/ion.rangeSlider.skinFlat.css" rel="stylesheet">
<!-- Datatables -->
<link href="/isard-sso-admin/vendors/datatables.net-bs/css/dataTables.bootstrap.min.css" rel="stylesheet">
<link href="/vendors/datatables.net-bs/css/dataTables.bootstrap.min.css" rel="stylesheet">
<!-- PNotify -->
<link href="/isard-sso-admin/vendors/pnotify/dist/pnotify.css" media="all" rel="stylesheet" type="text/css" />
<link href="/isard-sso-admin/vendors/pnotify/dist/pnotify.buttons.css" media="all" rel="stylesheet" type="text/css" />
<link href="/vendors/pnotify/dist/pnotify.css" media="all" rel="stylesheet" type="text/css" />
<link href="/vendors/pnotify/dist/pnotify.buttons.css" media="all" rel="stylesheet" type="text/css" />
<!-- iCheck -->
<link href="/isard-sso-admin/vendors/iCheck/skins/flat/green.css" rel="stylesheet">
<link href="/isard-sso-admin/vendors/select2/dist/css/select2.min.css" rel="stylesheet">
<link href="/vendors/iCheck/skins/flat/green.css" rel="stylesheet">
<link href="/vendors/select2/dist/css/select2.min.css" rel="stylesheet">
{% block css %}{% endblock %}
<!-- Custom Theme Style -->
<link href="/isard-sso-admin/build/css/custom.css" rel="stylesheet">
<link href="/build/css/custom.css" rel="stylesheet">
<!-- Isard Style Sheet-->
<link href="/isard-sso-admin/static/dd.css" rel="stylesheet">
<link href="/static/dd.css" rel="stylesheet">
</head>
<body class="nav-md">
@ -64,44 +64,44 @@
<!-- jQuery -->
<script src="/isard-sso-admin/vendors/jquery/dist/jquery.js"></script>
<script src="/vendors/jquery/dist/jquery.js"></script>
<!-- Bootstrap -->
<script src="/isard-sso-admin/vendors/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="/vendors/bootstrap/dist/js/bootstrap.min.js"></script>
<!-- NProgress -->
<script src="/isard-sso-admin/vendors/nprogress/nprogress.js"></script>
<script src="/vendors/nprogress/nprogress.js"></script>
<!-- Datatables -->
<script src="/isard-sso-admin/vendors/datatables.net/js/jquery.dataTables.min.js"></script>
<script src="/isard-sso-admin/vendors/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
<script src="/vendors/datatables.net/js/jquery.dataTables.min.js"></script>
<script src="/vendors/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
<!-- Ion.RangeSlider -->
<script src="/isard-sso-admin/vendors/ion.rangeSlider/js/ion.rangeSlider.min.js"></script>
<script src="/vendors/ion.rangeSlider/js/ion.rangeSlider.min.js"></script>
<!-- PNotify -->
<script type="text/javascript" src="/isard-sso-admin/vendors/pnotify/dist/pnotify.js"></script>
<script type="text/javascript" src="/isard-sso-admin/vendors/pnotify/dist/pnotify.confirm.js"></script>
<script type="text/javascript" src="/isard-sso-admin/vendors/pnotify/dist/pnotify.buttons.js"></script>
<script type="text/javascript" src="/vendors/pnotify/dist/pnotify.js"></script>
<script type="text/javascript" src="/vendors/pnotify/dist/pnotify.confirm.js"></script>
<script type="text/javascript" src="/vendors/pnotify/dist/pnotify.buttons.js"></script>
<!-- validator -->
<script src="/isard-sso-admin/vendors/validator/validator.js"></script>
<script src="/vendors/validator/validator.js"></script>
<!-- Parsley -->
<script src="/isard-sso-admin/vendors/parsleyjs/dist/parsley.min.js"></script>
<script src="/vendors/parsleyjs/dist/parsley.min.js"></script>
<!-- moment -->
<script src="/isard-sso-admin/vendors/moment/min/moment.min.js"></script>
<script src="/vendors/moment/min/moment.min.js"></script>
<!-- validator -->
<script src="/isard-sso-admin/vendors/iCheck/icheck.min.js"></script>
<script src="/vendors/iCheck/icheck.min.js"></script>
<!-- bootstrap-progressbar -->
<script src="/isard-sso-admin/vendors/bootstrap-progressbar/bootstrap-progressbar.min.js"></script>
<script src="/vendors/bootstrap-progressbar/bootstrap-progressbar.min.js"></script>
<!-- ECharts -->
<script src="/isard-sso-admin/vendors/echarts/dist/echarts.min.js"></script>
<script src="/vendors/echarts/dist/echarts.min.js"></script>
<!-- Select2 -->
<script src="/isard-sso-admin/vendors/select2/dist/js/select2.full.min.js"></script>
<script src="/vendors/select2/dist/js/select2.full.min.js"></script>
<!-- SocketIO -->
<script src="/isard-sso-admin/static/vendor/socket.io-2.3.1.slim.js"></script>
<script src="/isard-sso-admin/static/js/status_socket.js"></script>
<script src="/static/vendor/socket.io-2.3.1.slim.js"></script>
<script src="/static/js/status_socket.js"></script>
<!-- isard initializers -->
<script src="/isard-sso-admin/static/dd.js"></script>
<script src="/static/dd.js"></script>
<!-- Requirements for fancy tree -->
<script src="/isard-sso-admin/static/vendor/fancytree/src/jquery-ui-dependencies/jquery-ui.min.js"></script>
<script src="/isard-sso-admin/static/vendor/fancytree/dist/jquery.fancytree.min.js"></script>
<script src="/isard-sso-admin/static/vendor/fancytree/src/jquery.fancytree.table.js"></script>
<script src="/static/vendor/fancytree/src/jquery-ui-dependencies/jquery-ui.min.js"></script>
<script src="/static/vendor/fancytree/dist/jquery.fancytree.min.js"></script>
<script src="/static/vendor/fancytree/src/jquery.fancytree.table.js"></script>
<!-- flashed messages with pnotify -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
@ -112,7 +112,7 @@
text: "{{ message }}",
hide: true,
delay: 2000,
//~ icon: 'fa fa-alert-sign',
/~ icon: 'fa fa-alert-sign',
opacity: 1,
type: "{{ category }}",
addclass: "pnotify-center"

View File

@ -1,6 +1,6 @@
<footer>
<div class="pull-right">
Digital Democratic - Administration | <a href="https://gitlab.com/digitaldemocratic/digitaldemocratic">gitlab</a>
Digital Democratic - Administration | <a href="https:/gitlab.com/digitaldemocratic/digitaldemocratic">gitlab</a>
</div>
<div class="clearfix"></div>
</footer>

View File

@ -7,12 +7,12 @@
<ul class="nav navbar-nav navbar-right">
<li class="">
<a href="javascript:" class="user-profile dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<img src="/isard-sso-admin/static/img/user.png" alt="..." >
<img src="/static/img/user.png" alt="..." >
<span class=" fa fa-angle-down"></span>
</a>
<ul class="dropdown-menu dropdown-usermenu pull-right">
<li><a href="/isard-sso-admin/profile"><i class="fa fa-gear pull-right"></i> Profile</a></li>
<li><a href="/isard-sso-admin/logout"><i class="fa fa-sign-out pull-right"></i> Log Out</a></li>
<li><a href="/profile"><i class="fa fa-gear pull-right"></i> Profile</a></li>
<li><a href="/logout"><i class="fa fa-sign-out pull-right"></i> Log Out</a></li>
</ul>
</li>

View File

@ -10,16 +10,16 @@
<title>Login | Digital Democratic</title>
<!-- Bootstrap -->
<link href="/isard-sso-admin/vendors/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="/vendors/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="/isard-sso-admin/vendors/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<link href="/vendors/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<!-- Animate.css -->
<link href="/isard-sso-admin/vendors/animate.css/animate.min.css" rel="stylesheet">
<link href="/vendors/animate.css/animate.min.css" rel="stylesheet">
<!-- PNotify -->
<link href="/isard-sso-admin/vendors/pnotify/dist/pnotify.css" media="all" rel="stylesheet" type="text/css" />
<link href="/isard-sso-admin/vendors/pnotify/dist/pnotify.buttons.css" media="all" rel="stylesheet" type="text/css" />
<link href="/vendors/pnotify/dist/pnotify.css" media="all" rel="stylesheet" type="text/css" />
<link href="/vendors/pnotify/dist/pnotify.buttons.css" media="all" rel="stylesheet" type="text/css" />
<!-- Custom Theme Style -->
<link href="/isard-sso-admin/build/css/custom.min.css" rel="stylesheet">
<link href="/build/css/custom.min.css" rel="stylesheet">
</head>
<body class="login">
@ -47,7 +47,7 @@
<div>
<h1><i class="fa fa-user"></i> Digital Democratic</h1>
<p>©2020 All Rights Reserved. <a href="https://gitlab.com/digitaldemocratic/digitaldemocratic/LICENSE" target="_blank">AGPLv3</a></p>
<p>©2020 All Rights Reserved. <a href="https:/gitlab.com/digitaldemocratic/digitaldemocratic/LICENSE" target="_blank">AGPLv3</a></p>
</div>
</div>
</form>
@ -58,11 +58,11 @@
</body>
<!-- jQuery -->
<script src="/isard-sso-admin/vendors/jquery/dist/jquery.min.js"></script>
<script src="/vendors/jquery/dist/jquery.min.js"></script>
<!-- PNotify -->
<script type="text/javascript" src="/isard-sso-admin/vendors/pnotify/dist/pnotify.js"></script>
<script type="text/javascript" src="/isard-sso-admin/vendors/pnotify/dist/pnotify.confirm.js"></script>
<script type="text/javascript" src="/isard-sso-admin/vendors/pnotify/dist/pnotify.buttons.js"></script>
<script type="text/javascript" src="/vendors/pnotify/dist/pnotify.js"></script>
<script type="text/javascript" src="/vendors/pnotify/dist/pnotify.confirm.js"></script>
<script type="text/javascript" src="/vendors/pnotify/dist/pnotify.buttons.js"></script>
<script>PNotify.prototype.options.styling = "bootstrap3";</script>
{% with messages = get_flashed_messages(with_categories=true) %}
@ -73,7 +73,7 @@
title: "{{ nav }}",
text: "{{ message }}",
hide: true,
//~ icon: 'fa fa-alert-sign',
/~ icon: 'fa fa-alert-sign',
opacity: 1,
type: "error",
addclass: "pnotify-center"
@ -83,5 +83,5 @@
{% endif %}
{% endwith %}
<!-- Isard restful ajax calls -->
<script src="/isard-sso-admin/static/js/restful.js"></script>
<script src="/static/js/restful.js"></script>
</html>

View File

@ -10,14 +10,14 @@
<title>Page not found! | Digital Democratic</title>
<!-- Bootstrap -->
<link href="../isard-sso-admin/vendors/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="../vendors/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="../isard-sso-admin/vendors/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<link href="../vendors/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<!-- NProgress -->
<link href="../isard-sso-admin/vendors/nprogress/nprogress.css" rel="stylesheet">
<link href="../vendors/nprogress/nprogress.css" rel="stylesheet">
<!-- Custom Theme Style -->
<link href="../isard-sso-admin/build/css/custom.min.css" rel="stylesheet">
<link href="../build/css/custom.min.css" rel="stylesheet">
</head>
<body class="nav-md">
@ -29,8 +29,8 @@
<div class="text-center text-center">
<h1 class="error-number">404</h1>
<h2>Sorry but we couldn't find this page</h2>
<p>This page you are looking for does not exist <a href="https://gitlab.com/digitaldemocratic/digitaldemocratic">Report this?</a>
<a href="/isard-sso-admin/login">Go back to login page</a>
<p>This page you are looking for does not exist <a href="https:/gitlab.com/digitaldemocratic/digitaldemocratic">Report this?</a>
<a href="/login">Go back to login page</a>
</p>
<!--
<div class="mid_center">
@ -55,15 +55,15 @@
</div>
<!-- jQuery -->
<script src="../isard-sso-admin/vendors/jquery/dist/jquery.min.js"></script>
<script src="../vendors/jquery/dist/jquery.min.js"></script>
<!-- Bootstrap -->
<script src="../isard-sso-admin/vendors/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="../vendors/bootstrap/dist/js/bootstrap.min.js"></script>
<!-- FastClick -->
<script src="../isard-sso-admin/vendors/fastclick/lib/fastclick.js"></script>
<script src="../vendors/fastclick/lib/fastclick.js"></script>
<!-- NProgress -->
<script src="../isard-sso-admin/vendors/nprogress/nprogress.js"></script>
<script src="../vendors/nprogress/nprogress.js"></script>
<!-- Custom Theme Scripts -->
<script src="../isard-sso-admin/build/js/custom.min.js"></script>
<script src="../build/js/custom.min.js"></script>
</body>
</html>

View File

@ -10,14 +10,14 @@
<title>Page not allowed! | Digital Democratic</title>
<!-- Bootstrap -->
<link href="../isard-sso-admin/vendors/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="../vendors/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="../isard-sso-admin/vendors/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<link href="../vendors/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<!-- NProgress -->
<link href="../isard-sso-admin/vendors/nprogress/nprogress.css" rel="stylesheet">
<link href="../vendors/nprogress/nprogress.css" rel="stylesheet">
<!-- Custom Theme Style -->
<link href="../isard-sso-admin/build/css/custom.min.css" rel="stylesheet">
<link href="../build/css/custom.min.css" rel="stylesheet">
</head>
<body class="nav-md">
@ -29,8 +29,8 @@
<div class="text-center">
<h1 class="error-number">500</h1>
<h2>Internal Server Error</h2>
<p>We track these errors automatically, but if the problem persists feel free to contact us. In the meantime, try refreshing. <a href="https://gitlab.com/digitaldemocratic/digitaldemocratic">Report this?</a>
<a href="/isard-sso-admin/login">Go back to login page</a>
<p>We track these errors automatically, but if the problem persists feel free to contact us. In the meantime, try refreshing. <a href="https:/gitlab.com/digitaldemocratic/digitaldemocratic">Report this?</a>
<a href="/login">Go back to login page</a>
</p>
<!--
<div class="mid_center">
@ -55,15 +55,15 @@
</div>
<!-- jQuery -->
<script src="../isard-sso-admin/vendors/jquery/dist/jquery.min.js"></script>
<script src="../vendors/jquery/dist/jquery.min.js"></script>
<!-- Bootstrap -->
<script src="../isard-sso-admin/vendors/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="../vendors/bootstrap/dist/js/bootstrap.min.js"></script>
<!-- FastClick -->
<script src="../isard-sso-admin/vendors/fastclick/lib/fastclick.js"></script>
<script src="../vendors/fastclick/lib/fastclick.js"></script>
<!-- NProgress -->
<script src="../isard-sso-admin/vendors/nprogress/nprogress.js"></script>
<script src="../vendors/nprogress/nprogress.js"></script>
<!-- Custom Theme Scripts -->
<script src="../isard-sso-admin/build/js/custom.min.js"></script>
<script src="../build/js/custom.min.js"></script>
</body>
</html>

View File

@ -6,19 +6,19 @@
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="container for-about text-center" style="margin-top: 15px;">
<img src="/isard-sso-admin/static/img/dd.svg" width="250px" height="250px">
<img src="/static/img/dd.svg" width="250px" height="250px">
<h1>Digital Democratic</h1>
<h1><small>Schools apps integrations</small></h1>
<div class="row" style="margin-top: 40px;">
<div class="col-lg-2 col-md-12 col-sm-12 col-xs-12"></div>
<div class="col-lg-2 col-md-6 col-sm-6 col-xs-12">
<a href="https://gitlab.com/digitaldemocratic/digitaldemocratic" target="_blank" style="color: deepskyblue">
<a href="https:/gitlab.com/digitaldemocratic/digitaldemocratic" target="_blank" style="color: deepskyblue">
<i class="fa fa-globe" style="font-size: 125px;" aria-hidden="true"></i>
<h1><small>Visit website</small></h1>
</a>
</div>
<div class="col-lg-2 col-md-6 col-sm-6 col-xs-12">
<a href="https://gitlab.com/digitaldemocratic/digitaldemocratic/-/issues" target="_blank" style="color: orange">
<a href="https:/gitlab.com/digitaldemocratic/digitaldemocratic/-/issues" target="_blank" style="color: orange">
<i class="fa fa-gitlab fa-5x" style="font-size: 125px;" aria-hidden="true"></i>
<h1><small>Open an issue</small></h1>
</a>
@ -38,7 +38,7 @@
</h1>
</div>
<div class="col-md-2 col-sm-6 col-xs-12">
<p><img src="/isard-sso-admin/static/img/agplv3-155x51.png" style="margin-top: 60px;"></p>
<p><img src="/static/img/agplv3-155x51.png" style="margin-top: 60px;"></p>
<h1 style="margin-top: 25px;"><small>License</small></h1>
</div>
<div class="col-md-4 col-sm-4 col-xs-4"></div>
@ -51,7 +51,7 @@
{% endblock %}
{% block pagescript %}
<script src="/isard-sso-admin/static/js/restful.js"></script>
<script src="/static/js/restful.js"></script>
<script src="/isard-sso-admin/static/js/status_socket.js"></script>
<script src="/static/js/status_socket.js"></script>
{% endblock %}

View File

@ -2,9 +2,9 @@
{% extends "base.html" %}
{% block css %}
<!-- Ion.RangeSlider -->
<link href="/isard-sso-admin/vendors/normalize-css/normalize.css" rel="stylesheet">
<link href="/vendors/normalize-css/normalize.css" rel="stylesheet">
<!-- Switchery -->
<link href="/isard-sso-admin/vendors/switchery/dist/switchery.min.css" rel="stylesheet">
<link href="/vendors/switchery/dist/switchery.min.css" rel="stylesheet">
{% endblock %}
{% block content %}
@ -49,11 +49,11 @@
{% block pagescript %}
<!-- Ion.RangeSlider -->
<script src="/isard-sso-admin/vendors/ion.rangeSlider/js/ion.rangeSlider.min.js"></script>
<script src="/vendors/ion.rangeSlider/js/ion.rangeSlider.min.js"></script>
<!-- iCheck -->
<script src="/isard-sso-admin/vendors/iCheck/icheck.min.js"></script>
<script src="/vendors/iCheck/icheck.min.js"></script>
<!-- Switchery -->
<script src="/isard-sso-admin/vendors/switchery/dist/switchery.min.js"></script>
<script src="/vendors/switchery/dist/switchery.min.js"></script>
<!-- Desktops sse & modals -->
<script src="/isard-sso-admin/static/js/groups.js"></script>
<script src="/static/js/groups.js"></script>
{% endblock %}

View File

@ -115,6 +115,11 @@
<div class="modal-body">
<form id="modalPasswdUserForm" class="form-inline form-label-left">
<div class="x_content" style="padding: 0px;">
<div class="row">
This is a proposed password.<br>
Change it for the one desired for this user. <br>
REMEMBER TO COPY THIS PASSWORD AS IT IS THE ONLY TIME YOU WILL SEE IT
</div>
<div class="row">
<div class="col-md-12 col-xs-12">
<input id="id" hidden/>
@ -211,7 +216,7 @@
</div>
<div class="row">
<div class="col-md-12 col-xs-12">
<label class="control-label" for="id">Group</label>
<label class="control-label" for="id">Groups</label>
<select class="groups-select roundbox" name="groups[]" multiple="multiple" style="width:100%">
</select>
</div>
@ -225,7 +230,7 @@
</div>
<div class="x_content" style="padding: 0px;">
<div class="row">
<div class="col-md-4 col-xs-12">
<!-- <div class="col-md-4 col-xs-12">
<label class="control-label" for="id">Moodle</label>
<select class="role-moodle-select" name="moodle" style="width:100%">
</select>
@ -234,9 +239,9 @@
<label class="control-label" for="id">Nextcloud</label>
<select class="role-nextcloud-select" name="nextcloud" style="width:100%">
</select>
</div>
</div> -->
<div class="col-md-4 col-xs-12">
<label class="control-label" for="id">Keycloak</label>
<label class="control-label" for="id">Role</label>
<select class="role-keycloak-select" name="keycloak" style="width:100%">
</select>
</div>

View File

@ -2,9 +2,9 @@
{% extends "base.html" %}
{% block css %}
<!-- Ion.RangeSlider -->
<link href="/isard-sso-admin/vendors/normalize-css/normalize.css" rel="stylesheet">
<link href="/vendors/normalize-css/normalize.css" rel="stylesheet">
<!-- Switchery -->
<link href="/isard-sso-admin/vendors/switchery/dist/switchery.min.css" rel="stylesheet">
<link href="/vendors/switchery/dist/switchery.min.css" rel="stylesheet">
{% endblock %}
{% block content %}
@ -42,11 +42,11 @@
{% block pagescript %}
<!-- Ion.RangeSlider -->
<script src="/isard-sso-admin/vendors/ion.rangeSlider/js/ion.rangeSlider.min.js"></script>
<script src="/vendors/ion.rangeSlider/js/ion.rangeSlider.min.js"></script>
<!-- iCheck -->
<script src="/isard-sso-admin/vendors/iCheck/icheck.min.js"></script>
<script src="/vendors/iCheck/icheck.min.js"></script>
<!-- Switchery -->
<script src="/isard-sso-admin/vendors/switchery/dist/switchery.min.js"></script>
<script src="/vendors/switchery/dist/switchery.min.js"></script>
<!-- Desktops sse & modals -->
<script src="/isard-sso-admin/static/js/roles.js"></script>
<script src="/static/js/roles.js"></script>
{% endblock %}

View File

@ -2,9 +2,9 @@
{% extends "base.html" %}
{% block css %}
<!-- Ion.RangeSlider -->
<link href="/isard-sso-admin/vendors/normalize-css/normalize.css" rel="stylesheet">
<link href="/vendors/normalize-css/normalize.css" rel="stylesheet">
<!-- Switchery -->
<link href="/isard-sso-admin/vendors/switchery/dist/switchery.min.css" rel="stylesheet">
<link href="/vendors/switchery/dist/switchery.min.css" rel="stylesheet">
{% endblock %}
{% block content %}
@ -72,16 +72,16 @@
</div>
</div>
{% include 'pages/modals/external_modals.html' %}
{% include 'pages/sysadmin/modals/external_modals.html' %}
{% endblock %}
{% block pagescript %}
<!-- Ion.RangeSlider -->
<script src="/isard-sso-admin/vendors/ion.rangeSlider/js/ion.rangeSlider.min.js"></script>
<script src="/vendors/ion.rangeSlider/js/ion.rangeSlider.min.js"></script>
<!-- iCheck -->
<script src="/isard-sso-admin/vendors/iCheck/icheck.min.js"></script>
<script src="/vendors/iCheck/icheck.min.js"></script>
<!-- Switchery -->
<script src="/isard-sso-admin/vendors/switchery/dist/switchery.min.js"></script>
<script src="/vendors/switchery/dist/switchery.min.js"></script>
<!-- Desktops sse & modals -->
<script src="/isard-sso-admin/static/js/external.js"></script>
<script src="/static/js/external.js"></script>
{% endblock %}

View File

@ -0,0 +1,81 @@
<!-- extend base layout -->
{% extends "base.html" %}
{% block css %}
<!-- Ion.RangeSlider -->
<link href="/vendors/normalize-css/normalize.css" rel="stylesheet">
<!-- Switchery -->
<link href="/vendors/switchery/dist/switchery.min.css" rel="stylesheet">
{% endblock %}
{% block content %}
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h3><i class="fa fa-user"></i> Users</h3>
<ul class="nav navbar-right panel_toolbox">
<li>
<a class="btn-new-user"><span style="color: #5499c7; "><i class="fa fa-plus"></i> Add new</span></a>
</li>
</ul>
<div class="clearfix"></div>
</div>
<div class="x_content">
<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>
{% if current_user.role =='sysadmin' %}
<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>
<th></th>
<th>Avatar</th>
<th>Username</th>
<th>First</th>
<th>Last</th>
<th>email</th>
<th>Keycloak</th>
<th>K.Groups</th>
<th>K.Roles</th>
<th>Moodle</th>
<th>M.Groups</th>
<th>Nextcloud</th>
<th>N.Groups</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
{% include 'pages/modals/users_modals.html' %}
{% include 'pages/users_detail.html' %}
</div>
</div>
{% endblock %}
{% block pagescript %}
<!-- Ion.RangeSlider -->
<script src="/vendors/ion.rangeSlider/js/ion.rangeSlider.min.js"></script>
<!-- iCheck -->
<script src="/vendors/iCheck/icheck.min.js"></script>
<!-- Switchery -->
<script src="/vendors/switchery/dist/switchery.min.js"></script>
<!-- Desktops sse & modals -->
<script src="/static/js/sysadmin/users.js"></script>
{% endblock %}

View File

@ -2,9 +2,9 @@
{% extends "base.html" %}
{% block css %}
<!-- Ion.RangeSlider -->
<link href="/isard-sso-admin/vendors/normalize-css/normalize.css" rel="stylesheet">
<link href="/vendors/normalize-css/normalize.css" rel="stylesheet">
<!-- Switchery -->
<link href="/isard-sso-admin/vendors/switchery/dist/switchery.min.css" rel="stylesheet">
<link href="/vendors/switchery/dist/switchery.min.css" rel="stylesheet">
{% endblock %}
{% block content %}
@ -21,13 +21,13 @@
<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>
{% if current_user.role =='admin-keycloak' %}
<button class="btn btn-danger btn-xs btn-delete_keycloak">
<i class="fa fa-trash"></i> Delete all keycloak
</button>
@ -43,17 +43,15 @@
<tr>
<th></th>
<th>Avatar</th>
<th>Enabled</th>
<th>Username</th>
<th>Actions</th>
<th>First</th>
<th>Last</th>
<th>email</th>
<th>Keycloak</th>
<th>K.Groups</th>
<th>K.Roles</th>
<th>Moodle</th>
<th>M.Groups</th>
<th>Nextcloud</th>
<th>N.Groups</th>
<th>Email</th>
<th>Groups</th>
<th>Roles</th>
</tr>
</thead>
<tbody>
@ -71,11 +69,11 @@
{% block pagescript %}
<!-- Ion.RangeSlider -->
<script src="/isard-sso-admin/vendors/ion.rangeSlider/js/ion.rangeSlider.min.js"></script>
<script src="/vendors/ion.rangeSlider/js/ion.rangeSlider.min.js"></script>
<!-- iCheck -->
<script src="/isard-sso-admin/vendors/iCheck/icheck.min.js"></script>
<script src="/vendors/iCheck/icheck.min.js"></script>
<!-- Switchery -->
<script src="/isard-sso-admin/vendors/switchery/dist/switchery.min.js"></script>
<script src="/vendors/switchery/dist/switchery.min.js"></script>
<!-- Desktops sse & modals -->
<script src="/isard-sso-admin/static/js/users.js"></script>
<script src="/static/js/users.js"></script>
{% endblock %}

View File

@ -1,6 +1,6 @@
<div class="navbar nav_title" style="border: 0;">
<a href="/isard-sso-admin/about" class="site_title">
<img src="/isard-sso-admin/static/img/dd.svg" class="sidebar_logo logo_white" alt="dd">
<a href="/about" class="site_title">
<img src="/custom/img/logo.png" class="sidebar_logo logo_white" alt="dd">
<span>Digital Democratic</span>
</a>
</div>
@ -13,13 +13,19 @@
<div class="clearfix"></div>
<ul class="nav side-menu">
<li><a class="btn-global-resync"><span style="color: #c75454; "><i class="fa fa-refresh"></i> Resync</span></a></li>
<li><a href="/isard-sso-admin/users"><i class="fa fa-user"></i> Users</a></li>
<li><a href="/isard-sso-admin/groups"><i class="fa fa-users"></i> Groups</a></li>
<li><a href="/isard-sso-admin/roles"><i class="fa fa-user-secret"></i> Roles</a></li>
<li><a href="/isard-sso-admin/external"><i class="fa fa-external-link"></i> External</a></li>
<li><a href="/users"><i class="fa fa-user"></i> Users</a></li>
<li><a href="/groups"><i class="fa fa-users"></i> Groups</a></li>
<li><a href="/roles"><i class="fa fa-user-secret"></i> Roles</a></li>
{% if current_user.role == 'admin' %}
<h3>System Admin</h3>
<div class="clearfix"></div>
<li><a href="/sysadmin/users"><i class="fa fa-user"></i> SysAdminUsers</span></a></li>
<li><a href="/sysadmin/external"><i class="fa fa-external-link"></i> External</a></li>
{% endif %}
</ul>
<ul class="nav side-menu">
<li><a href="/isard-sso-admin/about"><i class="fa fa-question"></i> About</span></a>
<li><a href="/about"><i class="fa fa-question"></i> About</span></a>
</li>
</ul>
</div>

View File

@ -0,0 +1,145 @@
#!flask/bin/python
# coding=utf-8
from admin import app
import logging as log
import traceback
from uuid import uuid4
import time,json
import sys,os
from flask import render_template, Response, request, redirect, url_for, jsonify
import concurrent.futures
from flask_login import login_required
# import Queue
import threading
threads={}
# q = Queue.Queue()
from pprint import pprint
from keycloak.exceptions import KeycloakGetError
@app.route('/api/resync')
@login_required
def resync():
return json.dumps(app.admin.resync_data()), 200, {'Content-Type': 'application/json'}
@app.route('/api/users', methods=['GET'])
@app.route('/api/users/<provider>', methods=['POST', 'PUT', 'GET', 'DELETE'])
@login_required
def users(provider=False):
if request.method == 'DELETE':
if provider == 'keycloak':
return json.dumps(app.admin.delete_keycloak_users()), 200, {'Content-Type': 'application/json'}
if provider == 'nextcloud':
return json.dumps(app.admin.delete_nextcloud_users()), 200, {'Content-Type': 'application/json'}
if provider == 'moodle':
return json.dumps(app.admin.delete_moodle_users()), 200, {'Content-Type': 'application/json'}
if request.method == 'POST':
if provider == 'moodle':
return json.dumps(app.admin.sync_to_moodle()), 200, {'Content-Type': 'application/json'}
if provider == 'nextcloud':
return json.dumps(app.admin.sync_to_nextcloud()), 200, {'Content-Type': 'application/json'}
return json.dumps(app.admin.get_mix_users()), 200, {'Content-Type': 'application/json'}
# Update pwd
@app.route('/api/user_password', methods=['GET'])
@app.route('/api/user_password/<userid>', methods=['PUT'])
@login_required
def user_password(userid=False):
if request.method == 'GET':
return json.dumps(app.admin.get_dice_pwd()), 200, {'Content-Type': 'application/json'}
if request.method == 'PUT':
data=request.get_json(force=True)
password=data['password']
temporary=data.get('temporary',True)
try:
res = app.admin.user_update_password(userid,password,temporary)
return json.dumps({}), 200, {'Content-Type': 'application/json'}
except KeycloakGetError as e:
print(e.error_message.decode("utf-8"))
return e.error_message, e.response_code, {'Content-Type': 'application/json'}
return json.dumps({}), 301, {'Content-Type': 'application/json'}
# User
@app.route('/api/user/<userid>', methods=['POST', 'PUT', 'GET', 'DELETE'])
@login_required
def user(userid=None):
if request.method == 'DELETE':
res = app.admin.delete_user(userid)
return json.dumps({}), 200, {'Content-Type': 'application/json'}
# return json.dumps(), 301, {'Content-Type': 'application/json'}
if request.method == 'POST':
pass
if request.method == 'PUT':
pass
if request.method == 'DELETE':
pass
if request.method == 'GET':
res = app.admin.get_user(userid)
return json.dumps(res), 200, {'Content-Type': 'application/json'}
@app.route('/api/roles')
@login_required
def roles():
sorted_roles = sorted(app.admin.get_roles(), key=lambda k: k['name'])
return json.dumps(sorted_roles), 200, {'Content-Type': 'application/json'}
@app.route('/api/groups')
@app.route('/api/groups/<provider>', methods=['POST', 'PUT', 'GET', 'DELETE'])
@login_required
def groups(provider=False):
if request.method == 'GET':
sorted_groups = sorted(app.admin.get_mix_groups(), key=lambda k: k['name'])
return json.dumps(sorted_groups), 200, {'Content-Type': 'application/json'}
if request.method == 'DELETE':
if provider == 'keycloak':
return json.dumps(app.admin.delete_keycloak_groups()), 200, {'Content-Type': 'application/json'}
### SYSADM USERS ONLY
@app.route('/api/external', methods=['POST', 'PUT', 'GET'])
@login_required
def external():
if 'external' in threads.keys():
if threads['external'] is not None and threads['external'].is_alive():
return json.dumps({}), 301, {'Content-Type': 'application/json'}
else:
threads['external']=None
data=request.get_json(force=True)
if request.method == 'POST':
if data['format']=='json-ga':
threads['external'] = threading.Thread(target=app.admin.upload_json_ga, args=(data,))
threads['external'].start()
return json.dumps({}), 200, {'Content-Type': 'application/json'}
if data['format']=='csv-ug':
threads['external'] = threading.Thread(target=app.admin.upload_csv_ug, args=(data,))
threads['external'].start()
return json.dumps({}), 200, {'Content-Type': 'application/json'}
if request.method == 'PUT':
threads['external'] = threading.Thread(target=app.admin.sync_external, args=(data,))
threads['external'].start()
return json.dumps({}), 200, {'Content-Type': 'application/json'}
return json.dumps({}), 500, {'Content-Type': 'application/json'}
@app.route('/api/external/users')
@login_required
def external_users_list():
return json.dumps(app.admin.get_external_users()), 200, {'Content-Type': 'application/json'}
@app.route('/api/external/groups')
@login_required
def external_groups_list():
return json.dumps(app.admin.get_external_groups()), 200, {'Content-Type': 'application/json'}
@app.route('/api/external/roles', methods=['PUT'])
@login_required
def external_roles():
if request.method == 'PUT':
return json.dumps(app.admin.external_roleassign(request.get_json(force=True))), 200, {'Content-Type': 'application/json'}

View File

@ -1,25 +0,0 @@
#!flask/bin/python
# coding=utf-8
from admin import app
import logging as log
import traceback
from uuid import uuid4
import time,json
import sys,os
from flask import render_template, Response, request, redirect, url_for, jsonify, send_file
from flask_login import login_required
from pprint import pprint
from ..lib.avatars import Avatars
avatars=Avatars()
@app.route('/isard-sso-admin/avatar/<username>', methods=['GET'])
@login_required
def avatar(username):
userid=avatars.username2id(username)
if userid:
return send_file('../avatars/master-avatars/'+userid, mimetype='image/jpeg')
return send_file('static/img/usera.jpg', mimetype='image/jpeg')

View File

@ -5,7 +5,8 @@ from flask import render_template, flash, request, redirect, url_for
from ..auth.authentication import *
from flask_login import login_required, current_user, login_user, logout_user
@app.route('/isard-sso-admin/login', methods=['GET', 'POST'])
@app.route('/', methods=['GET', 'POST'])
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
if request.form['user'] == '' or request.form['password'] == '':
@ -18,12 +19,12 @@ def login():
user=User({'id': ram_user['id'], 'password': ram_user['password'], 'role': ram_user['role'], 'active': True})
login_user(user)
flash('Logged in successfully.','success')
return redirect(url_for('users'))
return redirect(url_for('web_users'))
else:
flash('Username not found or incorrect password.','warning')
return render_template('login.html')
@app.route('/isard-sso-admin/logout', methods=['GET'])
@app.route('/logout', methods=['GET'])
@login_required
def logout():
logout_user()

View File

@ -1,144 +0,0 @@
#!flask/bin/python
# coding=utf-8
from admin import app
import logging as log
import traceback
from uuid import uuid4
import time,json
import sys,os
from flask import render_template, Response, request, redirect, url_for, jsonify
import concurrent.futures
from flask_login import login_required
from pprint import pprint
# from flask_socketio import SocketIO, emit, join_room, leave_room, \
# close_room, rooms, disconnect, send
# socketio = SocketIO(app)
# from flask_login import login_required
# from flask_oidc import OpenIDConnect
from ..auth.authentication import oidc
@app.route('/isard-sso-admin/custom_callback')
@oidc.custom_callback
def callback(data):
return 'Hello. You submitted %s' % data
@app.route('/isard-sso-admin/private')
@oidc.require_login
def hello_me():
info = oidc.user_getinfo(['email', 'openid_id'])
return ('Hello, %s (%s)! <a href="/">Return</a>' %
(info.get('email'), info.get('openid_id')))
@app.route('/isard-sso-admin/api')
@oidc.accept_token(True, ['openid'])
def hello_api():
return json.dumps({'hello': 'Welcome %s' % g.oidc_token_info['sub']})
@app.route('/isard-sso-admin/logout')
def logoutoidc():
oidc.logout()
return 'Hi, you have been logged out! <a href="/">Return</a>'
@app.route('/isard-sso-admin/resync')
@login_required
def resync():
return json.dumps(app.admin.resync_data()), 200, {'Content-Type': 'application/json'}
@app.route('/isard-sso-admin/users', methods=['GET'])
@app.route('/isard-sso-admin/users/<provider>', methods=['POST', 'PUT', 'GET', 'DELETE'])
@login_required
def users(provider=False):
if request.method == 'DELETE':
if provider == 'keycloak':
return json.dumps(app.admin.delete_keycloak_users()), 200, {'Content-Type': 'application/json'}
if provider == 'nextcloud':
return json.dumps(app.admin.delete_nextcloud_users()), 200, {'Content-Type': 'application/json'}
if provider == 'moodle':
return json.dumps(app.admin.delete_moodle_users()), 200, {'Content-Type': 'application/json'}
if request.method == 'POST':
if provider == 'moodle':
return json.dumps(app.admin.sync_to_moodle()), 200, {'Content-Type': 'application/json'}
if provider == 'nextcloud':
return json.dumps(app.admin.sync_to_nextcloud()), 200, {'Content-Type': 'application/json'}
return render_template('pages/users.html', title="Users", nav="Users")
@app.route('/isard-sso-admin/users_list')
@login_required
def users_list():
return json.dumps(app.admin.get_mix_users()), 200, {'Content-Type': 'application/json'}
@app.route('/isard-sso-admin/roles')
@login_required
def roles():
return render_template('pages/roles.html', title="Roles", nav="Roles")
@app.route('/isard-sso-admin/roles_list')
@login_required
def roles_list():
return json.dumps(app.admin.get_roles()), 200, {'Content-Type': 'application/json'}
@app.route('/isard-sso-admin/groups')
@app.route('/isard-sso-admin/groups/<provider>', methods=['POST', 'PUT', 'GET', 'DELETE'])
@login_required
def groups(provider=False):
if request.method == 'DELETE':
if provider == 'keycloak':
return json.dumps(app.admin.delete_keycloak_groups()), 200, {'Content-Type': 'application/json'}
return render_template('pages/groups.html', title="Groups", nav="Groups")
@app.route('/isard-sso-admin/groups_list')
@login_required
def groups_list():
return json.dumps(app.admin.get_mix_groups()), 200, {'Content-Type': 'application/json'}
@app.route('/isard-sso-admin/external', methods=['POST', 'PUT', 'GET'])
@login_required
def external():
if request.method == 'POST':
data=request.get_json(force=True)
if data['format']=='json-ga':
app.admin.upload_json_ga(data)
if data['format']=='csv-ug':
app.admin.upload_csv_ug(data)
return json.dumps({}), 200, {'Content-Type': 'application/json'}
if request.method == 'PUT':
return json.dumps(app.admin.sync_external(request.get_json(force=True))), 200, {'Content-Type': 'application/json'}
return render_template('pages/external.html', title="External", nav="External")
@app.route('/isard-sso-admin/external_users_list')
@login_required
def external_users_list():
return json.dumps(app.admin.get_external_users()), 200, {'Content-Type': 'application/json'}
@app.route('/isard-sso-admin/external_groups_list')
@login_required
def external_groups_list():
return json.dumps(app.admin.get_external_groups()), 200, {'Content-Type': 'application/json'}
@app.route('/isard-sso-admin/external/roles', methods=['PUT'])
@login_required
def external_roles():
if request.method == 'PUT':
return json.dumps(app.admin.external_roleassign(request.get_json(force=True))), 200, {'Content-Type': 'application/json'}
def WaitStatus(self, desktop_id, original_status, transition_status, final_status):
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
future = executor.submit(lambda p: self._wait_for_domain_status(*p), [desktop_id, original_status, transition_status, final_status])
try:
result = future.result()
except ReqlTimeoutError:
raise DesktopActionTimeout
except DesktopWaitFailed:
raise DesktopActionFailed
return True

View File

@ -6,14 +6,14 @@
# # socketio = SocketIO(app)
# # from ...start import socketio
# @socketio.on('connect', namespace='/isard-sso-admin/sio')
# @socketio.on('connect', namespace='//sio')
# def socketio_connect():
# join_room('admin')
# socketio.emit('update',
# json.dumps('Joined'),
# namespace='/isard-sso-admin/sio',
# namespace='//sio',
# room='admin')
# @socketio.on('disconnect', namespace='/isard-sso-admin/sio')
# @socketio.on('disconnect', namespace='//sio')
# def socketio_domains_disconnect():
# None

View File

@ -0,0 +1,80 @@
#!flask/bin/python
# coding=utf-8
from admin import app
import logging as log
import traceback
from uuid import uuid4
import time,json
import sys,os
from flask import render_template, Response, request, redirect, url_for, jsonify, send_file
import concurrent.futures
from flask_login import login_required
from pprint import pprint
from ..lib.avatars import Avatars
avatars=Avatars()
''' OIDC TESTS '''
# from ..auth.authentication import oidc
# @app.route('/custom_callback')
# @oidc.custom_callback
# def callback(data):
# return 'Hello. You submitted %s' % data
# @app.route('/private')
# @oidc.require_login
# def hello_me():
# info = oidc.user_getinfo(['email', 'openid_id'])
# return ('Hello, %s (%s)! <a href="/">Return</a>' %
# (info.get('email'), info.get('openid_id')))
# @app.route('/api')
# @oidc.accept_token(True, ['openid'])
# def hello_api():
# return json.dumps({'hello': 'Welcome %s' % g.oidc_token_info['sub']})
# @app.route('/logout')
# def logoutoidc():
# oidc.logout()
# return 'Hi, you have been logged out! <a href="/">Return</a>'
''' OIDC TESTS '''
@app.route('/users')
@login_required
def web_users():
return render_template('pages/users.html', title="Users", nav="Users")
@app.route('/roles')
@login_required
def web_roles():
return render_template('pages/roles.html', title="Roles", nav="Roles")
@app.route('/groups')
@login_required
def web_groups(provider=False):
return render_template('pages/groups.html', title="Groups", nav="Groups")
@app.route('/avatar/<userid>', methods=['GET'])
@login_required
def avatar(userid):
if userid != 'false':
return send_file('../avatars/master-avatars/'+userid, mimetype='image/jpeg')
return send_file('static/img/missing.jpg', mimetype='image/jpeg')
### SYS ADMIN
@app.route('/sysadmin/users')
@login_required
def web_sysadmin_users():
return render_template('pages/sysadmin/users.html', title="SysAdmin Users", nav="SysAdminUsers")
@app.route('/sysadmin/external')
@login_required
## SysAdmin role
def web_sysadmin_external():
return render_template('pages/sysadmin/external.html', title="External", nav="External")

View File

@ -1,13 +1,13 @@
{
"web": {
"auth_uri": "https://sso.santantoni.duckdns.org/auth/realms/master/protocol/openid-connect/auth",
"auth_uri": "https://sso.[[DOMAIN]]/auth/realms/master/protocol/openid-connect/auth",
"client_id": "adminapp",
"client_secret": "8a9e5a2e-3be9-43e3-9c47-1796f0d5ab72",
"redirect_uris": [
"https://sso.santantoni.duckdns.org/isard-sso-admin/custom_callback"
"https://sso.[[DOMAIN]]/oidc_callback"
],
"userinfo_uri": "https://sso.santantoni.duckdns.org/auth/realms/master/protocol/openid-connect/userinfo",
"token_uri": "https://sso.santantoni.duckdns.org/auth/realms/master/protocol/openid-connect/token",
"token_introspection_uri": "https://sso.santantoni.duckdns.org/auth/realms/master/protocol/openid-connect/token/introspect"
"userinfo_uri": "https://sso.[[DOMAIN]]/auth/realms/master/protocol/openid-connect/userinfo",
"token_uri": "https://sso.[[DOMAIN]]/auth/realms/master/protocol/openid-connect/token",
"token_introspection_uri": "https://sso.[[DOMAIN]]/auth/realms/master/protocol/openid-connect/token/introspect"
}
}

View File

@ -8,34 +8,21 @@ from flask_socketio import SocketIO, emit, join_room, leave_room, \
import json
from admin import app
# socketio.init_app(app, cors_allowed_origins="*")
# from admin.views.Socketio import *
app.socketio = SocketIO(app)
# app.socketio.init_app(app, cors_allowed_origins="*")
@app.socketio.on('connect', namespace='/isard-sso-admin/sio')
@app.socketio.on('connect', namespace='/sio')
def socketio_connect():
join_room('admin')
app.socketio.emit('update',
json.dumps('Joined'),
namespace='/isard-sso-admin/sio',
namespace='/sio',
room='admin')
# socketio.emit('update',
# json.dumps('DATA SENT'),
# namespace='/isard-sso-admin/sio',
# room='admin')
@app.socketio.on('disconnect', namespace='/isard-sso-admin/sio')
def socketio_domains_disconnect():
@app.socketio.on('disconnect', namespace='/sio')
def socketio_disconnect():
None
if __name__ == '__main__':
app.socketio.run(app,host='0.0.0.0', port=9000, debug=False, cors_allowed_origins="*", ssl_context='adhoc', async_mode="threading") #, logger=logger, engineio_logger=engineio_logger)
app.socketio.run(app,host='0.0.0.0', port=9000, debug=False, ssl_context='adhoc', async_mode="threading") #, logger=logger, engineio_logger=engineio_logger)
# , cors_allowed_origins="*"
# /usr/lib/python3.8/site-packages/certifi

View File

@ -47,6 +47,7 @@ frontend website
acl is_sso hdr_beg(host) sso.
acl is_ipa hdr_beg(host) ipa.
acl is_api hdr_beg(host) api.
acl is_admin hdr_beg(host) admin.
use_backend be_nextcloud if is_nextcloud
use_backend be_moodle if is_moodle
@ -56,7 +57,7 @@ frontend website
use_backend be_etherpad if is_pad
use_backend be_admin if is_sso { path_beg /socket.io }
use_backend be_adminer if is_sso { path_beg /isard-sso-adminer }
use_backend be_admin if is_sso { path_beg /isard-sso-admin }
use_backend be_admin if is_admin
use_backend be_sso if is_sso
use_backend be_ipa if is_ipa
use_backend be_api if is_api