mirror of
https://github.com/ail-project/ail-framework.git
synced 2024-11-26 15:57:16 +00:00
chg: [user] refactor user creation and edit + edit user organisation
This commit is contained in:
parent
5c903f9f88
commit
496d19aa19
8 changed files with 125 additions and 42 deletions
|
@ -71,6 +71,20 @@ def get_orgs():
|
||||||
def is_user_in_org(org_uuid, user_id):
|
def is_user_in_org(org_uuid, user_id):
|
||||||
return r_serv_db.sadd(f'ail:org:{org_uuid}:users', user_id)
|
return r_serv_db.sadd(f'ail:org:{org_uuid}:users', user_id)
|
||||||
|
|
||||||
|
def get_orgs_selector():
|
||||||
|
orgs = []
|
||||||
|
for org_uuid in get_orgs():
|
||||||
|
org = Organisation(org_uuid)
|
||||||
|
name = org.get_name()
|
||||||
|
orgs.append({'uuid': org_uuid, 'name': name})
|
||||||
|
return orgs
|
||||||
|
|
||||||
|
def create_default_org():
|
||||||
|
# org = Organisation(generate_uuid())
|
||||||
|
name = 'Default AIL Organisation'
|
||||||
|
description = 'Default AIL Organisation'
|
||||||
|
return create_org(name, description)
|
||||||
|
|
||||||
#### ORGANISATION ####
|
#### ORGANISATION ####
|
||||||
|
|
||||||
class Organisation:
|
class Organisation:
|
||||||
|
@ -138,6 +152,9 @@ class Organisation:
|
||||||
meta['date_created'] = self._get_field('date_created')
|
meta['date_created'] = self._get_field('date_created')
|
||||||
return meta
|
return meta
|
||||||
|
|
||||||
|
def is_user(self, user_id):
|
||||||
|
return r_serv_db.sismember(f'ail:org:{self.uuid}:users', user_id)
|
||||||
|
|
||||||
def add_user(self, user_id):
|
def add_user(self, user_id):
|
||||||
r_serv_db.sadd(f'ail:org:{self.uuid}:users', user_id)
|
r_serv_db.sadd(f'ail:org:{self.uuid}:users', user_id)
|
||||||
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'org', self.uuid)
|
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'org', self.uuid)
|
||||||
|
@ -189,6 +206,7 @@ def create_org(name, description, uuid=None, nationality=None, sector=None, org_
|
||||||
|
|
||||||
org = Organisation(uuid)
|
org = Organisation(uuid)
|
||||||
org.create(name, description, nationality=nationality, sector=sector, org_type=org_type, logo=logo)
|
org.create(name, description, nationality=nationality, sector=sector, org_type=org_type, logo=logo)
|
||||||
|
return org
|
||||||
|
|
||||||
def get_org_objs_by_type(org_uuid, obj_type):
|
def get_org_objs_by_type(org_uuid, obj_type):
|
||||||
return r_serv_db.smembers(f'org:{org_uuid}:{obj_type}')
|
return r_serv_db.smembers(f'org:{org_uuid}:{obj_type}')
|
||||||
|
|
|
@ -104,6 +104,12 @@ def hashing_password(password):
|
||||||
def get_user_passwd_hash(user_id):
|
def get_user_passwd_hash(user_id):
|
||||||
return r_serv_db.hget('ail:users:all', user_id)
|
return r_serv_db.hget('ail:users:all', user_id)
|
||||||
|
|
||||||
|
def remove_default_password():
|
||||||
|
# Remove default user password file
|
||||||
|
default_passwd_file = os.path.join(os.environ['AIL_HOME'], 'DEFAULT_PASSWORD')
|
||||||
|
if os.path.isfile(default_passwd_file):
|
||||||
|
os.remove(default_passwd_file)
|
||||||
|
|
||||||
## --PASSWORDS-- ##
|
## --PASSWORDS-- ##
|
||||||
|
|
||||||
def check_email(email):
|
def check_email(email):
|
||||||
|
@ -304,7 +310,7 @@ def disable_user(user_id):
|
||||||
def enable_user(user_id):
|
def enable_user(user_id):
|
||||||
r_serv_db.srem(f'ail:users:disabled', user_id)
|
r_serv_db.srem(f'ail:users:disabled', user_id)
|
||||||
|
|
||||||
def create_user(user_id, password=None, admin_id=None, chg_passwd=True, role=None, otp=False):
|
def create_user(user_id, password=None, admin_id=None, chg_passwd=True, org_uuid=None, role=None, otp=False):
|
||||||
# # TODO: check password strength
|
# # TODO: check password strength
|
||||||
if password:
|
if password:
|
||||||
new_password = password
|
new_password = password
|
||||||
|
@ -312,14 +318,8 @@ def create_user(user_id, password=None, admin_id=None, chg_passwd=True, role=Non
|
||||||
new_password = gen_password()
|
new_password = gen_password()
|
||||||
password_hash = hashing_password(new_password)
|
password_hash = hashing_password(new_password)
|
||||||
|
|
||||||
# EDIT
|
|
||||||
if exists_user(user_id):
|
|
||||||
if password or chg_passwd:
|
|
||||||
edit_user(user_id, password_hash, chg_passwd=chg_passwd, otp=otp)
|
|
||||||
if role:
|
|
||||||
edit_user_role(user_id, role)
|
|
||||||
# CREATE USER
|
# CREATE USER
|
||||||
elif admin_id:
|
if admin_id:
|
||||||
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'creator', admin_id)
|
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'creator', admin_id)
|
||||||
date = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
date = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'created_at', date)
|
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'created_at', date)
|
||||||
|
@ -334,6 +334,12 @@ def create_user(user_id, password=None, admin_id=None, chg_passwd=True, role=Non
|
||||||
r_serv_db.sadd(f'ail:users:role:{role_to_add}', user_id)
|
r_serv_db.sadd(f'ail:users:role:{role_to_add}', user_id)
|
||||||
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'role', role)
|
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'role', role)
|
||||||
|
|
||||||
|
# ORG
|
||||||
|
org = ail_orgs.Organisation(org_uuid)
|
||||||
|
if not org.exists():
|
||||||
|
raise Exception('Organisation does not exist')
|
||||||
|
org.add_user(user_id)
|
||||||
|
|
||||||
r_serv_db.hset('ail:users:all', user_id, password_hash)
|
r_serv_db.hset('ail:users:all', user_id, password_hash)
|
||||||
if chg_passwd:
|
if chg_passwd:
|
||||||
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'change_passwd', 'True')
|
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'change_passwd', 'True')
|
||||||
|
@ -344,31 +350,41 @@ def create_user(user_id, password=None, admin_id=None, chg_passwd=True, role=Non
|
||||||
if otp or is_2fa_enabled():
|
if otp or is_2fa_enabled():
|
||||||
enable_user_2fa(user_id)
|
enable_user_2fa(user_id)
|
||||||
|
|
||||||
|
# TODO edit_org
|
||||||
|
# TODO LOG
|
||||||
|
def edit_user(admin_id, user_id, password=None, chg_passwd=False, org_uuid=None, edit_otp=False, otp=True):
|
||||||
|
if password:
|
||||||
|
password_hash = hashing_password(password)
|
||||||
|
if chg_passwd:
|
||||||
|
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'change_passwd', 'True')
|
||||||
|
r_serv_db.hset('ail:users:all', user_id, password_hash)
|
||||||
|
|
||||||
def edit_user(user_id, password_hash, chg_passwd=False, otp=True):
|
# create new token
|
||||||
if chg_passwd:
|
generate_new_token(user_id)
|
||||||
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'change_passwd', 'True')
|
else:
|
||||||
r_serv_db.hset('ail:users:all', user_id, password_hash)
|
r_serv_db.hdel(f'ail:user:metadata:{user_id}', 'change_passwd')
|
||||||
|
|
||||||
# create new token
|
if org_uuid:
|
||||||
generate_new_token(user_id)
|
org = ail_orgs.Organisation(org_uuid)
|
||||||
else:
|
if org.exists():
|
||||||
r_serv_db.hdel(f'ail:user:metadata:{user_id}', 'change_passwd')
|
if not org.is_user(user_id):
|
||||||
|
current_org = ail_orgs.Organisation(get_user_org(user_id))
|
||||||
|
current_org.remove_user(user_id)
|
||||||
|
org.add_user(user_id)
|
||||||
|
|
||||||
# 2FA OTP
|
# 2FA OTP
|
||||||
if otp or is_2fa_enabled():
|
if edit_otp:
|
||||||
enable_user_2fa(user_id)
|
if otp or is_2fa_enabled():
|
||||||
else:
|
enable_user_2fa(user_id)
|
||||||
disable_user_2fa(user_id)
|
else:
|
||||||
|
disable_user_2fa(user_id)
|
||||||
|
|
||||||
date = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
date = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'last_edit', date)
|
r_serv_db.hset(f'ail:user:metadata:{user_id}', 'last_edit', date)
|
||||||
|
|
||||||
# Remove default user password file
|
# Remove default user password file
|
||||||
if user_id == 'admin@admin.test':
|
if user_id == 'admin@admin.test':
|
||||||
default_passwd_file = os.path.join(os.environ['AIL_HOME'], 'DEFAULT_PASSWORD')
|
remove_default_password()
|
||||||
if os.path.isfile(default_passwd_file):
|
|
||||||
os.remove(default_passwd_file)
|
|
||||||
|
|
||||||
## --USER-- ##
|
## --USER-- ##
|
||||||
|
|
||||||
|
@ -445,6 +461,8 @@ class AILUser(UserMixin):
|
||||||
meta['is_logged'] = is_user_logged(self.user_id)
|
meta['is_logged'] = is_user_logged(self.user_id)
|
||||||
if 'org' in options:
|
if 'org' in options:
|
||||||
meta['org'] = self.get_org()
|
meta['org'] = self.get_org()
|
||||||
|
if 'org_name' in options and meta['org']:
|
||||||
|
meta['org_name'] = ail_orgs.Organisation(self.get_org()).get_name()
|
||||||
return meta
|
return meta
|
||||||
|
|
||||||
## SESSION ##
|
## SESSION ##
|
||||||
|
@ -564,14 +582,14 @@ class AILUser(UserMixin):
|
||||||
|
|
||||||
def api_get_users_meta():
|
def api_get_users_meta():
|
||||||
meta = {'users': []}
|
meta = {'users': []}
|
||||||
options = {'api_key', 'creator', 'created_at', 'is_logged', 'last_edit', 'last_login', 'last_seen', 'last_seen_api', 'role', '2fa', 'otp_setup'}
|
options = {'api_key', 'creator', 'created_at', 'is_logged', 'last_edit', 'last_login', 'last_seen', 'last_seen_api', 'org', 'org_name', 'role', '2fa', 'otp_setup'}
|
||||||
for user_id in get_users():
|
for user_id in get_users():
|
||||||
user = AILUser(user_id)
|
user = AILUser(user_id)
|
||||||
meta['users'].append(user.get_meta(options=options))
|
meta['users'].append(user.get_meta(options=options))
|
||||||
return meta
|
return meta
|
||||||
|
|
||||||
def api_get_user_profile(user_id):
|
def api_get_user_profile(user_id):
|
||||||
options = {'api_key', 'role', '2fa'}
|
options = {'api_key', 'role', '2fa', 'org'}
|
||||||
user = AILUser(user_id)
|
user = AILUser(user_id)
|
||||||
if not user.exists():
|
if not user.exists():
|
||||||
return {'status': 'error', 'reason': 'User not found'}, 404
|
return {'status': 'error', 'reason': 'User not found'}, 404
|
||||||
|
@ -663,9 +681,23 @@ def api_create_user_api_key(user_id, admin_id, ip_address):
|
||||||
access_logger.info(f'New api key for user {user_id}', extra={'user_id': admin_id, 'ip_address': ip_address})
|
access_logger.info(f'New api key for user {user_id}', extra={'user_id': admin_id, 'ip_address': ip_address})
|
||||||
return user.new_api_key(), 200
|
return user.new_api_key(), 200
|
||||||
|
|
||||||
def api_create_user(admin_id, ip_address, user_id, password, role, otp):
|
def api_create_user(admin_id, ip_address, user_id, password, org_uuid, role, otp):
|
||||||
create_user(user_id, password=password, admin_id=admin_id, role=role, otp=otp)
|
user = AILUser(user_id)
|
||||||
access_logger.info(f'Create user {user_id}', extra={'user_id': admin_id, 'ip_address': ip_address})
|
if not user.exists():
|
||||||
|
create_user(user_id, password=password, admin_id=admin_id, org_uuid=org_uuid, role=role, otp=otp)
|
||||||
|
access_logger.info(f'Create user {user_id}', extra={'user_id': admin_id, 'ip_address': ip_address})
|
||||||
|
# Edit
|
||||||
|
else:
|
||||||
|
edit_user(admin_id, user_id, password, chg_passwd=True, org_uuid=org_uuid, edit_otp=True, otp=otp)
|
||||||
|
access_logger.info(f'Edit user {user_id}', extra={'user_id': admin_id, 'ip_address': ip_address})
|
||||||
|
|
||||||
|
def api_change_user_self_password(user_id, password):
|
||||||
|
if not check_password_strength(password):
|
||||||
|
return {'status': 'error', 'reason': 'Invalid Password'}, 400
|
||||||
|
password_hash = hashing_password(password)
|
||||||
|
user = AILUser(user_id)
|
||||||
|
user.edit_password(password_hash, chg_passwd=False)
|
||||||
|
return user_id, 200
|
||||||
|
|
||||||
def api_delete_user(user_id, admin_id, ip_address):
|
def api_delete_user(user_id, admin_id, ip_address):
|
||||||
user = AILUser(user_id)
|
user = AILUser(user_id)
|
||||||
|
|
|
@ -123,7 +123,7 @@ def user_migration():
|
||||||
if not chg_passwd:
|
if not chg_passwd:
|
||||||
chg_passwd = None
|
chg_passwd = None
|
||||||
|
|
||||||
ail_users.create_user(user_id, password=password_hash, chg_passwd=chg_passwd, role=role)
|
ail_users.create_user(user_id, password=password_hash, chg_passwd=chg_passwd, org_uuid=get_ail_uuid(), role=role)
|
||||||
print(user_id, token)
|
print(user_id, token)
|
||||||
|
|
||||||
for invite_row in r_crawler.smembers('telegram:invite_code'):
|
for invite_row in r_crawler.smembers('telegram:invite_code'):
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
Blueprint Flask: root endpoints: login, ...
|
Blueprint Flask: root endpoints: login, ...
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
@ -13,6 +14,8 @@ from flask import render_template, jsonify, request, Blueprint, redirect, url_fo
|
||||||
from flask import session
|
from flask import session
|
||||||
from flask_login import login_required, current_user, login_user, logout_user
|
from flask_login import login_required, current_user, login_user, logout_user
|
||||||
|
|
||||||
|
from blueprints.settings_b import create_json_response
|
||||||
|
|
||||||
sys.path.append('modules')
|
sys.path.append('modules')
|
||||||
|
|
||||||
# Import Role_Manager
|
# Import Role_Manager
|
||||||
|
@ -22,7 +25,7 @@ sys.path.append(os.environ['AIL_BIN'])
|
||||||
##################################
|
##################################
|
||||||
# Import Project packages
|
# Import Project packages
|
||||||
##################################
|
##################################
|
||||||
from lib.ail_users import AILUser, kill_sessions, create_user, check_password_strength, check_user_role_integrity
|
from lib.ail_users import AILUser, kill_sessions, api_change_user_self_password, check_password_strength, check_user_role_integrity
|
||||||
from lib.ConfigLoader import ConfigLoader
|
from lib.ConfigLoader import ConfigLoader
|
||||||
from lib import ail_logger
|
from lib import ail_logger
|
||||||
|
|
||||||
|
@ -48,7 +51,6 @@ root = Blueprint('root', __name__, template_folder='templates')
|
||||||
|
|
||||||
# ============ FUNCTIONS ============
|
# ============ FUNCTIONS ============
|
||||||
|
|
||||||
|
|
||||||
# ============= ROUTES ==============
|
# ============= ROUTES ==============
|
||||||
@root.route('/login', methods=['POST', 'GET']) # TODO LOG BRUTEFORCE ATTEMPT
|
@root.route('/login', methods=['POST', 'GET']) # TODO LOG BRUTEFORCE ATTEMPT
|
||||||
def login():
|
def login():
|
||||||
|
@ -273,13 +275,15 @@ def change_password():
|
||||||
if password1 == password2:
|
if password1 == password2:
|
||||||
if check_password_strength(password1):
|
if check_password_strength(password1):
|
||||||
user_id = current_user.get_user_id()
|
user_id = current_user.get_user_id()
|
||||||
create_user(user_id, password=password1, chg_passwd=False) # TODO RENAME ME
|
res = api_change_user_self_password(user_id, password1)
|
||||||
|
if res != 200:
|
||||||
|
return create_json_response(res[0], res[1])
|
||||||
access_logger.info(f'Password change', extra={'user_id': user_id, 'ip_address': request.remote_addr})
|
access_logger.info(f'Password change', extra={'user_id': user_id, 'ip_address': request.remote_addr})
|
||||||
# update Note
|
# update Note
|
||||||
# dashboard
|
# dashboard
|
||||||
return redirect(url_for('dashboard.index', update_note=True))
|
return redirect(url_for('dashboard.index', update_note=True))
|
||||||
else:
|
else:
|
||||||
error = 'Incorrect password'
|
error = 'Invalid password'
|
||||||
return render_template("change_password.html", error=error)
|
return render_template("change_password.html", error=error)
|
||||||
else:
|
else:
|
||||||
error = "Passwords don't match"
|
error = "Passwords don't match"
|
||||||
|
|
|
@ -220,7 +220,8 @@ def create_user():
|
||||||
return create_json_response(r[0], r[1])
|
return create_json_response(r[0], r[1])
|
||||||
meta = r[0]
|
meta = r[0]
|
||||||
all_roles = ail_users.get_all_roles()
|
all_roles = ail_users.get_all_roles()
|
||||||
return render_template("create_user.html", all_roles=all_roles, meta=meta,
|
orgs = ail_orgs.get_orgs_selector()
|
||||||
|
return render_template("create_user.html", all_roles=all_roles, orgs=orgs, meta=meta,
|
||||||
error=error, error_mail=error_mail,
|
error=error, error_mail=error_mail,
|
||||||
acl_admin=True)
|
acl_admin=True)
|
||||||
|
|
||||||
|
@ -240,6 +241,7 @@ def create_user_post():
|
||||||
admin_id = current_user.get_user_id()
|
admin_id = current_user.get_user_id()
|
||||||
|
|
||||||
email = request.form.get('username')
|
email = request.form.get('username')
|
||||||
|
org_uuid = request.form.get('user_organisation')
|
||||||
role = request.form.get('user_role')
|
role = request.form.get('user_role')
|
||||||
password1 = request.form.get('password1')
|
password1 = request.form.get('password1')
|
||||||
password2 = request.form.get('password2')
|
password2 = request.form.get('password2')
|
||||||
|
@ -266,14 +268,17 @@ def create_user_post():
|
||||||
else:
|
else:
|
||||||
password = ail_users.gen_password()
|
password = ail_users.gen_password()
|
||||||
|
|
||||||
if current_user.is_in_role('admin'):
|
if current_user.is_admin():
|
||||||
str_password = password
|
str_password = password
|
||||||
if ail_users.exists_user(email):
|
if ail_users.exists_user(email):
|
||||||
if not password1 and not password2:
|
if not password1 and not password2:
|
||||||
password = None
|
password = None
|
||||||
str_password = 'Password not changed'
|
str_password = 'Password not changed'
|
||||||
ail_users.api_create_user(admin_id, request.remote_addr, email, password, role, enable_2_fa)
|
edit = True
|
||||||
new_user = {'email': email, 'password': str_password, 'otp': enable_2_fa}
|
else:
|
||||||
|
edit = False
|
||||||
|
ail_users.api_create_user(admin_id, request.remote_addr, email, password, org_uuid, role, enable_2_fa)
|
||||||
|
new_user = {'email': email, 'password': str_password, 'org': org_uuid, 'otp': enable_2_fa, 'edited': edit}
|
||||||
return render_template("create_user.html", new_user=new_user, meta={}, all_roles=all_roles, acl_admin=True)
|
return render_template("create_user.html", new_user=new_user, meta={}, all_roles=all_roles, acl_admin=True)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -8,17 +8,25 @@ sys.path.append(os.environ['AIL_BIN'])
|
||||||
##################################
|
##################################
|
||||||
# Import Project packages
|
# Import Project packages
|
||||||
##################################
|
##################################
|
||||||
|
from lib import ail_orgs
|
||||||
from lib import ail_users
|
from lib import ail_users
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
# create role_list
|
|
||||||
ail_users._create_roles_list()
|
|
||||||
|
|
||||||
user_id = 'admin@admin.test'
|
user_id = 'admin@admin.test'
|
||||||
password = ail_users.gen_password()
|
password = ail_users.gen_password()
|
||||||
|
|
||||||
ail_users.create_user(user_id, password=password, admin_id='admin@admin.test', role='admin')
|
# create role_list
|
||||||
|
ail_users._create_roles_list()
|
||||||
|
|
||||||
|
if not ail_users.exists_user(user_id):
|
||||||
|
# Create Default Org
|
||||||
|
org = ail_orgs.create_default_org()
|
||||||
|
ail_users.create_user(user_id, password=password, admin_id='admin@admin.test', org_uuid=org.get_uuid(), role='admin')
|
||||||
|
# EDIT Password
|
||||||
|
else:
|
||||||
|
ail_users.edit_user('admin@admin.test', user_id, password=password, chg_passwd=True)
|
||||||
|
|
||||||
token = ail_users.get_default_admin_token()
|
token = ail_users.get_default_admin_token()
|
||||||
|
|
||||||
default_passwd_file = os.path.join(os.environ['AIL_HOME'], 'DEFAULT_PASSWORD')
|
default_passwd_file = os.path.join(os.environ['AIL_HOME'], 'DEFAULT_PASSWORD')
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<div class="text-center my-3 ">
|
<div class="text-center my-3 ">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
{% if new_user['edited']=='True' %}
|
{% if new_user['edited'] %}
|
||||||
<h5 class="card-title">User Edited</h5>
|
<h5 class="card-title">User Edited</h5>
|
||||||
{% else %}
|
{% else %}
|
||||||
<h5 class="card-title">User Created</h5>
|
<h5 class="card-title">User Created</h5>
|
||||||
|
@ -59,6 +59,17 @@
|
||||||
<div class="invalid-feedback">Please provide a valid email address</div>
|
<div class="invalid-feedback">Please provide a valid email address</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<label class="mt-3" for="role_selector">Organisation</label>
|
||||||
|
<select class="custom-select" id="role_selector" name="user_organisation">
|
||||||
|
{% for org in orgs %}
|
||||||
|
{% if meta['org'] == org['uuid'] %}
|
||||||
|
<option value="{{ org['uuid'] }}" selected>{{ org['uuid'] }} - {{ org['name'] }}</option>
|
||||||
|
{% else %}
|
||||||
|
<option value="{{ org['uuid'] }}">{{ org['uuid'] }} - {{ org['name'] }}</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
|
||||||
<label class="mt-3" for="role_selector">User Role</label>
|
<label class="mt-3" for="role_selector">User Role</label>
|
||||||
<select class="custom-select" id="role_selector" name="user_role">
|
<select class="custom-select" id="role_selector" name="user_role">
|
||||||
{% for role in all_roles %}
|
{% for role in all_roles %}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
<thead class="thead-dark">
|
<thead class="thead-dark">
|
||||||
<tr>
|
<tr>
|
||||||
<th>User</th>
|
<th>User</th>
|
||||||
|
<th>Org</th>
|
||||||
<th>Last Edit</th>
|
<th>Last Edit</th>
|
||||||
<th>Last Login</th>
|
<th>Last Login</th>
|
||||||
<th>Last Seen</th>
|
<th>Last Seen</th>
|
||||||
|
@ -46,6 +47,10 @@
|
||||||
{% for user in meta['users'] %}
|
{% for user in meta['users'] %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{user['id']}}</td>
|
<td>{{user['id']}}</td>
|
||||||
|
<td>
|
||||||
|
{{ user['org_name'] }}<br>
|
||||||
|
{{user['org']}}
|
||||||
|
</td>
|
||||||
<td>{{user['last_edit']}}</td>
|
<td>{{user['last_edit']}}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if user['last_login'] %}
|
{% if user['last_login'] %}
|
||||||
|
|
Loading…
Reference in a new issue