mirror of https://github.com/CIRCL/AIL-framework
chg: [user_management UI] add admin section: edit + create users
parent
9c2d290580
commit
5b58872b15
|
@ -7,6 +7,7 @@
|
||||||
import configparser
|
import configparser
|
||||||
import redis
|
import redis
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# FLASK #
|
# FLASK #
|
||||||
|
@ -175,6 +176,9 @@ max_dashboard_logs = int(cfg.get("Flask", "max_dashboard_logs"))
|
||||||
|
|
||||||
crawler_enabled = cfg.getboolean("Crawler", "activate_crawler")
|
crawler_enabled = cfg.getboolean("Crawler", "activate_crawler")
|
||||||
|
|
||||||
|
regex_password = r'^(?=(.*\d){2})(?=.*[a-z])(?=.*[A-Z]).{10,}$'
|
||||||
|
regex_password = re.compile(regex_password)
|
||||||
|
|
||||||
# VT
|
# VT
|
||||||
try:
|
try:
|
||||||
from virusTotalKEYS import vt_key
|
from virusTotalKEYS import vt_key
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*-coding:UTF-8 -*
|
# -*-coding:UTF-8 -*
|
||||||
|
|
||||||
|
import os
|
||||||
|
import redis
|
||||||
|
import bcrypt
|
||||||
|
import secrets
|
||||||
|
import configparser
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from flask_login import LoginManager, current_user, login_user, logout_user, login_required
|
from flask_login import LoginManager, current_user, login_user, logout_user, login_required
|
||||||
|
|
||||||
|
@ -9,6 +15,22 @@ from flask import request, current_app
|
||||||
login_manager = LoginManager()
|
login_manager = LoginManager()
|
||||||
login_manager.login_view = 'role'
|
login_manager.login_view = 'role'
|
||||||
|
|
||||||
|
# CONFIG #
|
||||||
|
configfile = os.path.join(os.environ['AIL_BIN'], 'packages/config.cfg')
|
||||||
|
if not os.path.exists(configfile):
|
||||||
|
raise Exception('Unable to find the configuration file. \
|
||||||
|
Did you set environment variables? \
|
||||||
|
Or activate the virtualenv.')
|
||||||
|
|
||||||
|
cfg = configparser.ConfigParser()
|
||||||
|
cfg.read(configfile)
|
||||||
|
|
||||||
|
r_serv_db = redis.StrictRedis(
|
||||||
|
host=cfg.get("ARDB_DB", "host"),
|
||||||
|
port=cfg.getint("ARDB_DB", "port"),
|
||||||
|
db=cfg.getint("ARDB_DB", "db"),
|
||||||
|
decode_responses=True)
|
||||||
|
|
||||||
def login_admin(func):
|
def login_admin(func):
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def decorated_view(*args, **kwargs):
|
def decorated_view(*args, **kwargs):
|
||||||
|
@ -28,3 +50,88 @@ def login_analyst(func):
|
||||||
return login_manager.unauthorized()
|
return login_manager.unauthorized()
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
return decorated_view
|
return decorated_view
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################
|
||||||
|
###############################################################
|
||||||
|
###############################################################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def create_user_db(username_id , password, default=False, role=None, update=False):
|
||||||
|
password = password.encode()
|
||||||
|
password_hash = hashing_password(password)
|
||||||
|
|
||||||
|
# create user token
|
||||||
|
token = secrets.token_urlsafe(41)
|
||||||
|
r_serv_db.hset('user:tokens', token, username_id)
|
||||||
|
r_serv_db.hset('user_metadata:{}'.format(username_id), 'token', token)
|
||||||
|
|
||||||
|
if update:
|
||||||
|
r_serv_db.hdel('user_metadata:{}'.format(username_id), 'change_passwd')
|
||||||
|
else:
|
||||||
|
if default:
|
||||||
|
r_serv_db.hset('user_metadata:{}'.format(username_id), 'change_passwd', True)
|
||||||
|
if role:
|
||||||
|
if role in get_all_role():
|
||||||
|
for role_to_add in get_all_user_role(role):
|
||||||
|
r_serv_db.sadd('user_role:{}'.format(role_to_add), username_id)
|
||||||
|
r_serv_db.hset('user_metadata:{}'.format(username_id), 'role', role)
|
||||||
|
|
||||||
|
r_serv_db.hset('user:all', username_id, password_hash)
|
||||||
|
|
||||||
|
def edit_user_db(user_id, role, password=None):
|
||||||
|
if password:
|
||||||
|
password_hash = hashing_password(password.encode())
|
||||||
|
r_serv_db.hset('user:all', user_id, password_hash)
|
||||||
|
|
||||||
|
current_role = r_serv_db.hget('user_metadata:{}'.format(user_id), 'role')
|
||||||
|
if role != current_role:
|
||||||
|
request_level = get_role_level(role)
|
||||||
|
current_role = get_role_level(current_role)
|
||||||
|
|
||||||
|
if current_role < request_level:
|
||||||
|
role_to_remove = get_user_role_by_range(current_role -1, request_level - 2)
|
||||||
|
print('to remove')
|
||||||
|
print(role_to_remove)
|
||||||
|
for role_id in role_to_remove:
|
||||||
|
r_serv_db.srem('user_role:{}'.format(role_id), user_id)
|
||||||
|
r_serv_db.hset('user_metadata:{}'.format(user_id), 'role', role)
|
||||||
|
else:
|
||||||
|
role_to_add = get_user_role_by_range(request_level -1, current_role)
|
||||||
|
print('to add')
|
||||||
|
print(role_to_add)
|
||||||
|
for role_id in role_to_add:
|
||||||
|
r_serv_db.sadd('user_role:{}'.format(role_id), user_id)
|
||||||
|
r_serv_db.hset('user_metadata:{}'.format(user_id), 'role', role)
|
||||||
|
|
||||||
|
def delete_user_db(user_id):
|
||||||
|
if r_serv_db.exists('user_metadata:{}'.format(user_id)):
|
||||||
|
print('r')
|
||||||
|
role_to_remove =get_all_role()
|
||||||
|
for role_id in role_to_remove:
|
||||||
|
r_serv_db.srem('user_role:{}'.format(role_id), user_id)
|
||||||
|
user_token = r_serv_db.hget('user_metadata:{}'.format(user_id), 'token')
|
||||||
|
r_serv_db.hdel('user:tokens', user_token)
|
||||||
|
r_serv_db.delete('user_metadata:{}'.format(user_id))
|
||||||
|
r_serv_db.hdel('user:all', user_id)
|
||||||
|
|
||||||
|
def hashing_password(bytes_password):
|
||||||
|
hashed = bcrypt.hashpw(bytes_password, bcrypt.gensalt())
|
||||||
|
return hashed
|
||||||
|
|
||||||
|
def get_all_role():
|
||||||
|
return r_serv_db.zrange('ail:all_role', 0, -1)
|
||||||
|
|
||||||
|
def get_role_level(role):
|
||||||
|
return int(r_serv_db.zscore('ail:all_role', role))
|
||||||
|
|
||||||
|
def get_all_user_role(user_role):
|
||||||
|
current_role_val = get_role_level(user_role)
|
||||||
|
return r_serv_db.zrange('ail:all_role', current_role_val -1, -1)
|
||||||
|
|
||||||
|
def get_user_role_by_range(inf, sup):
|
||||||
|
print(inf)
|
||||||
|
print(sup)
|
||||||
|
return r_serv_db.zrange('ail:all_role', inf, sup)
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
from flask import Flask, render_template, jsonify, request, Blueprint, redirect, url_for
|
from flask import Flask, render_template, jsonify, request, Blueprint, redirect, url_for
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
|
|
||||||
|
from Role_Manager import login_admin, login_analyst, create_user_db, edit_user_db, delete_user_db
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import secrets
|
import secrets
|
||||||
import datetime
|
import datetime
|
||||||
|
@ -24,6 +26,7 @@ max_preview_char = Flask_config.max_preview_char
|
||||||
max_preview_modal = Flask_config.max_preview_modal
|
max_preview_modal = Flask_config.max_preview_modal
|
||||||
REPO_ORIGIN = Flask_config.REPO_ORIGIN
|
REPO_ORIGIN = Flask_config.REPO_ORIGIN
|
||||||
dict_update_description = Flask_config.dict_update_description
|
dict_update_description = Flask_config.dict_update_description
|
||||||
|
regex_password = Flask_config.regex_password
|
||||||
|
|
||||||
settings = Blueprint('settings', __name__, template_folder='templates')
|
settings = Blueprint('settings', __name__, template_folder='templates')
|
||||||
|
|
||||||
|
@ -33,8 +36,12 @@ settings = Blueprint('settings', __name__, template_folder='templates')
|
||||||
def one():
|
def one():
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
#def get_v1.5_update_tags_backgroud_status():
|
def check_password_strength(password):
|
||||||
# return '38%'
|
result = regex_password.match(password)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
def generate_new_token(user_id):
|
def generate_new_token(user_id):
|
||||||
# create user token
|
# create user token
|
||||||
|
@ -89,6 +96,18 @@ def get_user_metadata(user_id):
|
||||||
user_metadata['api_key'] = r_serv_db.hget('user_metadata:{}'.format(user_id), 'token')
|
user_metadata['api_key'] = r_serv_db.hget('user_metadata:{}'.format(user_id), 'token')
|
||||||
return user_metadata
|
return user_metadata
|
||||||
|
|
||||||
|
def get_users_metadata(list_users):
|
||||||
|
users = []
|
||||||
|
for user in list_users:
|
||||||
|
users.append(get_user_metadata(user))
|
||||||
|
return users
|
||||||
|
|
||||||
|
def get_all_users():
|
||||||
|
return r_serv_db.hkeys('user:all')
|
||||||
|
|
||||||
|
def get_all_roles():
|
||||||
|
return r_serv_db.zrange('ail:all_role', 0, -1)
|
||||||
|
|
||||||
# ============= ROUTES ==============
|
# ============= ROUTES ==============
|
||||||
|
|
||||||
@settings.route("/settings/", methods=['GET'])
|
@settings.route("/settings/", methods=['GET'])
|
||||||
|
@ -113,6 +132,96 @@ def new_token():
|
||||||
generate_new_token(current_user.get_id())
|
generate_new_token(current_user.get_id())
|
||||||
return redirect(url_for('settings.edit_profile'))
|
return redirect(url_for('settings.edit_profile'))
|
||||||
|
|
||||||
|
@settings.route("/settings/new_token_user", methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def new_token_user():
|
||||||
|
user_id = request.args.get('user_id')
|
||||||
|
if r_serv_db.exists('user_metadata:{}'.format(user_id)):
|
||||||
|
generate_new_token(user_id)
|
||||||
|
return redirect(url_for('settings.users_list'))
|
||||||
|
|
||||||
|
@settings.route("/settings/create_user", methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def create_user():
|
||||||
|
user_id = request.args.get('user_id')
|
||||||
|
role = None
|
||||||
|
if r_serv_db.exists('user_metadata:{}'.format(user_id)):
|
||||||
|
role = r_serv_db.hget('user_metadata:{}'.format(user_id), 'role')
|
||||||
|
else:
|
||||||
|
user_id = None
|
||||||
|
all_roles = get_all_roles()
|
||||||
|
return render_template("create_user.html", all_roles=all_roles, user_id=user_id, user_role=role)
|
||||||
|
|
||||||
|
@settings.route("/settings/create_user_post", methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def create_user_post():
|
||||||
|
email = request.form.get('username')
|
||||||
|
role = request.form.get('user_role')
|
||||||
|
password1 = request.form.get('password1')
|
||||||
|
password2 = request.form.get('password2')
|
||||||
|
|
||||||
|
all_roles = get_all_roles()
|
||||||
|
|
||||||
|
if email and role:
|
||||||
|
if role in all_roles:
|
||||||
|
# password set
|
||||||
|
if password1 and password2:
|
||||||
|
if password1==password2:
|
||||||
|
if check_password_strength(password1):
|
||||||
|
password = password1
|
||||||
|
else:
|
||||||
|
return render_template("create_user.html", all_roles=all_roles)
|
||||||
|
else:
|
||||||
|
return render_template("create_user.html", all_roles=all_roles)
|
||||||
|
# generate password
|
||||||
|
else:
|
||||||
|
password = secrets.token_urlsafe()
|
||||||
|
|
||||||
|
if current_user.is_in_role('admin'):
|
||||||
|
# edit user
|
||||||
|
if r_serv_db.exists('user_metadata:{}'.format(email)):
|
||||||
|
if password1 and password2:
|
||||||
|
edit_user_db(email, password=password, role=role)
|
||||||
|
return redirect(url_for('settings.users_list', new_user=email, new_user_password=password, new_user_edited=True))
|
||||||
|
else:
|
||||||
|
edit_user_db(email, role=role)
|
||||||
|
return redirect(url_for('settings.users_list', new_user=email, new_user_password='Password not changed', new_user_edited=True))
|
||||||
|
# create user
|
||||||
|
else:
|
||||||
|
create_user_db(email, password, default=True, role=role)
|
||||||
|
return redirect(url_for('settings.users_list', new_user=email, new_user_password=password, new_user_edited=False))
|
||||||
|
|
||||||
|
else:
|
||||||
|
return render_template("create_user.html", all_roles=all_roles)
|
||||||
|
else:
|
||||||
|
return render_template("create_user.html", all_roles=all_roles)
|
||||||
|
|
||||||
|
@settings.route("/settings/users_list", methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def users_list():
|
||||||
|
all_users = get_users_metadata(get_all_users())
|
||||||
|
new_user = request.args.get('new_user')
|
||||||
|
new_user_dict = {}
|
||||||
|
if new_user:
|
||||||
|
new_user_dict['email'] = new_user
|
||||||
|
new_user_dict['edited'] = request.args.get('new_user_edited')
|
||||||
|
new_user_dict['password'] = request.args.get('new_user_password')
|
||||||
|
print(new_user)
|
||||||
|
return render_template("users_list.html", all_users=all_users, new_user=new_user_dict)
|
||||||
|
|
||||||
|
@settings.route("/settings/edit_user", methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def edit_user():
|
||||||
|
user_id = request.args.get('user_id')
|
||||||
|
return redirect(url_for('settings.create_user', user_id=user_id))
|
||||||
|
|
||||||
|
@settings.route("/settings/delete_user", methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
def delete_user():
|
||||||
|
user_id = request.args.get('user_id')
|
||||||
|
delete_user_db(user_id)
|
||||||
|
return redirect(url_for('settings.users_list'))
|
||||||
|
|
||||||
|
|
||||||
@settings.route("/settings/get_background_update_stats_json", methods=['GET'])
|
@settings.route("/settings/get_background_update_stats_json", methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Server Management - AIL</title>
|
||||||
|
<link rel="icon" href="{{ url_for('static', filename='image/ail-icon.png') }}">
|
||||||
|
|
||||||
|
<!-- Core CSS -->
|
||||||
|
<link href="{{ url_for('static', filename='css/bootstrap4.min.css') }}" rel="stylesheet">
|
||||||
|
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
|
||||||
|
<link href="{{ url_for('static', filename='css/dataTables.bootstrap4.min.css') }}" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- JS -->
|
||||||
|
<script src="{{ url_for('static', filename='js/jquery.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/popper.min.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/bootstrap4.min.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/jquery.dataTables.min.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/dataTables.bootstrap.min.js')}}"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
{% include 'nav_bar.html' %}
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
{% include 'settings/menu_sidebar.html' %}
|
||||||
|
|
||||||
|
<div class="col-12 col-xl-10" id="core_content">
|
||||||
|
|
||||||
|
<form class="form-signin" action="{{ url_for('settings.create_user_post')}}" autocomplete="off" method="post">
|
||||||
|
|
||||||
|
<h1 class="h3 mt-1 mb-3 text-center text-secondary">Create User</h1>
|
||||||
|
<label for="inputEmail" class="sr-only">Email address</label>
|
||||||
|
<input type="email" id="inputEmail" name="username" class="form-control" placeholder="Email address" autocomplete="off" required {% if user_id %}value="{{user_id}}"{% else %}{% endif %}>
|
||||||
|
|
||||||
|
<label class="mt-3" for="role_selector">User Role</label>
|
||||||
|
<select class="custom-select" id="role_selector" name="user_role">
|
||||||
|
{% for role in all_roles %}
|
||||||
|
{% if role == user_role %}
|
||||||
|
<option value="{{role}}" selected>{{role}}</option>
|
||||||
|
{% else %}
|
||||||
|
<option value="{{role}}">{{role}}</option>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div class="custom-control custom-switch mt-4 mb-3">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="set_manual_password" value="" onclick="toggle_password_fields();">
|
||||||
|
<label class="custom-control-label" for="set_manual_password">Set Password</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="password-section">
|
||||||
|
<h1 class="h3 mb-3 text-center text-secondary">Create Password</h1>
|
||||||
|
<label for="inputPassword1" class="sr-only">Password</label>
|
||||||
|
<input type="password" id="inputPassword1" name="password1" class="form-control" placeholder="Password" autocomplete="new-password">
|
||||||
|
<label for="inputPassword2" class="sr-only">Confirm Password</label>
|
||||||
|
<input type="password" id="inputPassword2" name="password2" class="form-control" placeholder="Confirm Password" value="" autocomplete="new-password">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-lg btn-primary btn-block mt-3" type="submit">Submit</button>
|
||||||
|
|
||||||
|
<div id="password-section-info">
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<h5 class="h3 mb-3 text-center text-secondary">Password Requirements</h5>
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
Minimal length
|
||||||
|
<span class="badge badge-primary badge-pill">10</span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
Upper characters: A-Z
|
||||||
|
<span class="badge badge-primary badge-pill">1</span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
Lower characters: a-z
|
||||||
|
<span class="badge badge-primary badge-pill">1</span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
Digits: 0-9
|
||||||
|
<span class="badge badge-primary badge-pill">2</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function(){
|
||||||
|
$("#password-section").hide();
|
||||||
|
$("#password-section-info").hide();
|
||||||
|
$("#nav_create_user").addClass("active");
|
||||||
|
$("#nav_user_management").removeClass("text-muted");
|
||||||
|
} );
|
||||||
|
|
||||||
|
function toggle_password_fields() {
|
||||||
|
var password_div = $("#password-section");
|
||||||
|
if(password_div.is(":visible")){
|
||||||
|
$("#password-section").hide();
|
||||||
|
$("#password-section-info").hide();
|
||||||
|
$("#inputPassword1").prop('required',false);
|
||||||
|
$("#inputPassword2").prop('required',false);
|
||||||
|
} else {
|
||||||
|
$("#password-section").show();
|
||||||
|
$("#password-section-info").show();
|
||||||
|
$("#inputPassword1").prop('required',true);
|
||||||
|
$("#inputPassword2").prop('required',true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
|
@ -27,11 +27,11 @@
|
||||||
|
|
||||||
{% include 'settings/menu_sidebar.html' %}
|
{% include 'settings/menu_sidebar.html' %}
|
||||||
|
|
||||||
<div class="col-12 col-lg-10" id="core_content">
|
<div class="col-12 col-xl-10" id="core_content">
|
||||||
|
|
||||||
<div class="card mb-3 mt-1">
|
<div class="card mb-3 mt-1">
|
||||||
<div class="card-header text-white bg-dark pb-1">
|
<div class="card-header text-white bg-dark pb-1">
|
||||||
<h5 class="card-title">AIL-framework Status :</h5>
|
<h5 class="card-title">My Profile :</h5>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Server Management - AIL</title>
|
||||||
|
<link rel="icon" href="{{ url_for('static', filename='image/ail-icon.png') }}">
|
||||||
|
|
||||||
|
<!-- Core CSS -->
|
||||||
|
<link href="{{ url_for('static', filename='css/bootstrap4.min.css') }}" rel="stylesheet">
|
||||||
|
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
|
||||||
|
<link href="{{ url_for('static', filename='css/dataTables.bootstrap4.min.css') }}" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- JS -->
|
||||||
|
<script src="{{ url_for('static', filename='js/jquery.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/popper.min.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/bootstrap4.min.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/jquery.dataTables.min.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/dataTables.bootstrap.min.js')}}"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.edit_icon:hover{
|
||||||
|
cursor: pointer;
|
||||||
|
color: #17a2b8;
|
||||||
|
}
|
||||||
|
.trash_icon:hover{
|
||||||
|
cursor: pointer;
|
||||||
|
color: #c82333;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
{% include 'nav_bar.html' %}
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
{% include 'settings/menu_sidebar.html' %}
|
||||||
|
|
||||||
|
<div class="col-12 col-xl-10" id="core_content">
|
||||||
|
|
||||||
|
{% if new_user %}
|
||||||
|
<div class="text-center my-3 ">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
{% if new_user['edited']=='True' %}
|
||||||
|
<h5 class="card-title">User Edited</h5>
|
||||||
|
{% else %}
|
||||||
|
<h5 class="card-title">User Created</h5>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>User: {{new_user['email']}}</p>
|
||||||
|
<p>Password: {{new_user['password']}}</p>
|
||||||
|
<a href="{{url_for('settings.users_list')}}" class="btn btn-primary"><i class="fas fa-eye-slash"></i> Hide</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="table-responsive mt-1 table-hover table-borderless table-striped">
|
||||||
|
<table class="table">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Role</th>
|
||||||
|
<th>Api Key</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="tbody_last_crawled">
|
||||||
|
{% for user in all_users %}
|
||||||
|
<tr>
|
||||||
|
<td>{{user['email']}}</td>
|
||||||
|
<td>{{user['role']}}</td>
|
||||||
|
<td>
|
||||||
|
{{user['api_key']}}
|
||||||
|
<a class="ml-3" href="{{url_for('settings.new_token_user')}}?user_id={{user['email']}}"><i class="fa fa-random"></i></a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="{{ url_for('settings.edit_user')}}?user_id={{user['email']}}">
|
||||||
|
<i class="fas fa-pencil-alt edit_icon"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{{ url_for('settings.delete_user')}}?user_id={{user['email']}}" class="ml-4">
|
||||||
|
<i class="fas fa-trash-alt trash_icon"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function(){
|
||||||
|
$("#nav_edit_profile").addClass("active");
|
||||||
|
$("#nav_user_management").removeClass("text-muted");
|
||||||
|
} );
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</html>
|
|
@ -38,18 +38,18 @@
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<nav class="navbar navbar-expand navbar-light bg-light flex-md-column flex-row align-items-start py-2" id="nav_users">
|
<nav class="navbar navbar-expand navbar-light bg-light flex-md-column flex-row align-items-start py-2" id="nav_users">
|
||||||
<h5 class="d-flex text-muted w-100">
|
<h5 class="d-flex text-muted w-100" id="nav_user_management">
|
||||||
<span>User Management</span>
|
<span>User Management</span>
|
||||||
</h5>
|
</h5>
|
||||||
<ul class="nav flex-md-column flex-row navbar-nav justify-content-between w-100"> <!--nav-pills-->
|
<ul class="nav flex-md-column flex-row navbar-nav justify-content-between w-100"> <!--nav-pills-->
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="{{url_for('hashDecoded.hashDecoded_page')}}" id="nav_dashboard">
|
<a class="nav-link" href="{{url_for('settings.create_user')}}" id="nav_create_user">
|
||||||
<i class="fas fa-user-plus"></i>
|
<i class="fas fa-user-plus"></i>
|
||||||
<span>Create User</span>
|
<span>Create User</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="{{url_for('hashDecoded.hashDecoded_page')}}" id="nav_dashboard">
|
<a class="nav-link" href="{{url_for('settings.users_list')}}" id="nav_users_list">
|
||||||
<i class="fas fa-users"></i>
|
<i class="fas fa-users"></i>
|
||||||
<span>Users List</span>
|
<span>Users List</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
Loading…
Reference in New Issue