v8.0: Refactor user module and simplify server status check

Refactor user-related modules, updating data handling, roles, and methods. Simplify server status check process by removing event-based handling and replacing it with straightforward AJAX requests.
pull/399/head
Aidaho 2024-08-03 09:25:02 +03:00
parent 2022681847
commit 108773c564
14 changed files with 145 additions and 305 deletions

View File

@ -90,7 +90,7 @@ def register_api_with_group(view, endpoint, url_beg, url_end, pk='user_id', pk_t
register_api(UserView, 'user', '/user', 'user_id')
register_api_with_group(UserGroupView, 'user_group', '/user', 'groups')
register_api_with_group(UserGroupView, 'user_group', 'user', 'groups')
bp.add_url_rule('/user/roles', view_func=UserRoles.as_view('roles'))
def register_api_channel(view, endpoint, url_beg, pk='receiver', pk_type='int', pk_end='channel_id', pk_type_end='int'):

View File

@ -1,11 +1,9 @@
#!/usr/bin/env python3.11
import distro
from app.modules.db.db_model import (
connect, Setting, Role, User, UserGroups, Groups, Services, RoxyTool, Version, SmonHttpCheck, GeoipCodes, SmonTcpCheck, SMON,
SmonPingCheck, migrate, mysql_enable
connect, Setting, Role, User, UserGroups, Groups, Services, RoxyTool, Version, GeoipCodes, migrate, mysql_enable
)
from peewee import DateTimeField, IntegerField, CharField, SQL
from peewee import IntegerField, CharField, SQL
conn = connect()
@ -105,9 +103,9 @@ def default_values():
print(str(e))
data_source = [
{'username': 'admin', 'email': 'admin@localhost', 'password': '21232f297a57a5a743894a0e4a801fc3', 'role': '1', 'group_id': '1'},
{'username': 'editor', 'email': 'editor@localhost', 'password': '5aee9dbd2a188839105073571bee1b1f', 'role': '2', 'group_id': '1'},
{'username': 'guest', 'email': 'guest@localhost', 'password': '084e0343a0486ff05530df6c705c8bb4', 'role': '4', 'group_id': '1'}
{'username': 'admin', 'email': 'admin@localhost', 'password': '21232f297a57a5a743894a0e4a801fc3', 'role_id': '1', 'group_id': '1'},
{'username': 'editor', 'email': 'editor@localhost', 'password': '5aee9dbd2a188839105073571bee1b1f', 'role_id': '2', 'group_id': '1'},
{'username': 'guest', 'email': 'guest@localhost', 'password': '084e0343a0486ff05530df6c705c8bb4', 'role_id': '4', 'group_id': '1'}
]
try:
@ -471,94 +469,6 @@ def update_db_v_4_3_0():
print("An error occurred:", e)
def update_db_v_6_3_13_1():
try:
SmonTcpCheck.insert_from(
SMON.select(SMON.id, SMON.ip, SMON.port).where(
(SMON.http == '') & (SMON.check_type == 'tcp')
), fields=[SmonTcpCheck.smon_id, SmonTcpCheck.ip, SmonTcpCheck.port]
).on_conflict_ignore().execute()
except Exception as e:
if e.args[0] == 'no such column: t1.name' or str(e) == 'type object \'SMON\' has no attribute \'ip\'':
print('Updating... DB has been updated to version 6.3.13-1')
else:
print("An error occurred:", e)
def update_db_v_6_3_13_2():
query = SMON.select().where(SMON.http != '')
try:
query_res = query.execute()
except Exception as e:
print("An error occurred:", e)
else:
for i in query_res:
try:
proto = i.http.split(':')[0]
uri = i.http.split(':')[1]
except Exception:
proto = ''
uri = ''
url = f'{proto}://{i.name}:{i.port}{uri}'
SmonHttpCheck.insert(smon_id=i.id, url=url, body=i.body).on_conflict_ignore().execute()
def update_db_v_6_3_13_3():
try:
SmonPingCheck.insert_from(
SMON.select(SMON.id, SMON.ip).where(SMON.check_type == 'ping'), fields=[SmonPingCheck.smon_id, SmonPingCheck.ip]
).on_conflict_ignore().execute()
except Exception as e:
if e.args[0] == 'duplicate column name: haproxy' or str(e) == 'type object \'SMON\' has no attribute \'ip\'':
print('Updating... DB has been updated to version 6.3.13-2')
else:
print("An error occurred:", e)
def update_db_v_6_3_13_4():
try:
migrate(
migrator.alter_column_type('smon', 'time_state', DateTimeField()),
migrator.rename_column('smon', 'ip', 'name'),
migrator.drop_column('smon', 'script', cascade=False),
migrator.drop_column('smon', 'http_status', cascade=False),
)
except Exception as e:
if e.args[0] == 'duplicate column name: check_type' or str(e) == '(1091, "Can\'t DROP COLUMN `script`; check that it exists")':
print('Updating... DB has been updated to version 6.3.13-3')
elif e.args[0] == 'duplicate column name: check_type' or str(e) == '(1091, "Can\'t DROP COLUMN `http_status`; check that it exists")':
print('Updating... DB has been updated to version 6.3.13-3')
elif e.args[0] == 'table smon__tmp__ has no column named UNIQUE' or str(e) == "'bool' object has no attribute 'sql'":
print('Updating... DB has been updated to version 6.3.13-3')
else:
print("An error occurred:", e)
def update_db_v_6_3_13_5():
try:
SMON.update(check_type='http').where(SMON.http != '').execute()
except Exception as e:
print("An error occurred:", e)
def update_db_v_6_3_17():
try:
Setting.delete().where(Setting.param == 'lists_path').execute()
except Exception as e:
print("An error occurred:", e)
else:
print("Updating... DB has been updated to version 6.3.17")
def update_db_v_6_3_18():
try:
Setting.delete().where(Setting.param == 'ssl_local_path').execute()
except Exception as e:
print("An error occurred:", e)
else:
print("Updating... DB has been updated to version 6.3.18")
def update_db_v_7_1_2():
try:
Setting.delete().where(Setting.param == 'stats_user').execute()
@ -666,6 +576,7 @@ def update_db_v_7_3_1():
def update_db_v_7_4():
try:
migrate(
migrator.rename_column('user', 'role', 'role_id'),
migrator.rename_column('backups', 'cred', 'cred_id'),
migrator.rename_column('backups', 'backup_type', 'type'),
migrator.rename_column('servers', 'active', 'haproxy_active'),
@ -687,7 +598,7 @@ def update_db_v_7_4():
migrator.rename_column('cred', 'groups', 'group_id'),
)
except Exception as e:
if e.args[0] == 'no such column: "cred"' or str(e) == '(1060, no such column: "cred")':
if e.args[0] == 'no such column: "role"' or str(e) == '(1060, no such column: "role")':
print("Updating... DB has been updated to version 7.4")
elif e.args[0] == "'bool' object has no attribute 'sql'":
print("Updating... DB has been updated to version 7.4")
@ -715,13 +626,6 @@ def update_all():
if check_ver() is None:
update_db_v_3_4_5_22()
update_db_v_4_3_0()
update_db_v_6_3_13_1()
update_db_v_6_3_13_2()
update_db_v_6_3_13_3()
update_db_v_6_3_13_4()
update_db_v_6_3_13_5()
update_db_v_6_3_17()
update_db_v_6_3_18()
update_db_v_7_1_2()
update_db_v_7_1_2_1()
update_db_v_7_2_0()

View File

@ -47,7 +47,7 @@ class User(BaseModel):
username = CharField(constraints=[SQL('UNIQUE')])
email = CharField(constraints=[SQL('UNIQUE')])
password = CharField(null=True)
role = CharField()
role_id = CharField()
group_id = CharField()
ldap_user = IntegerField(constraints=[SQL('DEFAULT "0"')])
enabled = IntegerField(constraints=[SQL('DEFAULT "1"')])

View File

@ -12,7 +12,7 @@ def add_user(user, email, password, role, enabled, group):
try:
hashed_pass = roxy_wi_tools.Tools.get_hash(password)
last_id = User.insert(
username=user, email=email, password=hashed_pass, role=role, enabled=enabled, group_id=group
username=user, email=email, password=hashed_pass, role_id=role, enabled=enabled, group_id=group
).execute()
except Exception as e:
out_error(e)
@ -31,14 +31,16 @@ def add_user(user, email, password, role, enabled, group):
def update_user(user, email, role, user_id, enabled):
try:
User.update(username=user, email=email, role=role, enabled=enabled).where(User.user_id == user_id).execute()
User.update(username=user, email=email, role_id=role, enabled=enabled).where(User.user_id == user_id).execute()
except Exception as e:
out_error(e)
def update_user_from_admin_area(user_id, **kwargs):
try:
User.update(**kwargs).where(User.user_id == user_id).execute()
query = User.update(**kwargs).where(User.user_id == user_id)
print(query)
query.execute()
except Exception as e:
out_error(e)
@ -70,6 +72,8 @@ def update_user_current_groups_by_id(groups, user_id):
def update_user_password(password, user_id):
if password == '':
return
try:
hashed_pass = roxy_wi_tools.Tools.get_hash(password)
user_update = User.update(password=hashed_pass).where(User.user_id == user_id)
@ -258,7 +262,7 @@ def get_super_admin_count() -> int:
def select_users_emails_by_group_id(group_id: int):
query = User.select(User.email).where((User.group_id == group_id) & (User.role != 'guest'))
query = User.select(User.email).where((User.group_id == group_id) & (User.role_id != 'guest'))
try:
query_res = query.execute()
except Exception as e:
@ -282,50 +286,6 @@ def is_user_super_admin(user_id: int) -> bool:
return False
def get_api_token(token):
try:
user_token = ApiToken.get(ApiToken.token == token)
except Exception as e:
return str(e)
else:
return True if token == user_token.token else False
def get_user_id_by_api_token(token):
query = (User.select(User.user_id).join(ApiToken, on=(
ApiToken.user_name == User.username
)).where(ApiToken.token == token))
try:
query_res = query.execute()
except Exception as e:
return str(e)
for i in query_res:
return i.user_id
def write_api_token(user_token, group_id, user_role, user_name):
token_ttl = int(get_setting('token_ttl'))
get_date = roxy_wi_tools.GetDate()
cur_date = get_date.return_date('regular', timedelta=token_ttl)
cur_date_token_ttl = get_date.return_date('regular', timedelta=token_ttl)
try:
ApiToken.insert(
token=user_token, user_name=user_name, user_group_id=group_id, user_role=user_role,
create_date=cur_date, expire_date=cur_date_token_ttl).execute()
except Exception as e:
out_error(e)
def get_username_group_id_from_api_token(token):
try:
user_name = ApiToken.get(ApiToken.token == token)
except Exception as e:
return str(e)
else:
return user_name.user_name, user_name.user_group_id, user_name.user_role
def get_role_id(user_id: int, group_id: int) -> int:
try:
role_id = UserGroups.get((UserGroups.user_id == user_id) & (UserGroups.user_group_id == group_id))

View File

@ -60,7 +60,7 @@ def is_admin(level=1, **kwargs):
def page_for_admin(level=1) -> None:
if not is_admin(level=level):
return abort(400, 'bad permission')
abort(400, 'bad permission')
def check_in_ldap(user, password):

View File

@ -83,15 +83,16 @@ class UdpListenerRequest(BaseModel):
class UserPost(BaseModel):
username: EscapedString
password: str
password: EscapedString
email: EscapedString
enabled: Optional[bool] = 1
user_group: int
role: Annotated[int, Gt(0), Le(4)] = 4
group_id: Optional[int] = 0
role_id: Annotated[int, Gt(0), Le(4)] = 4
class UserPut(BaseModel):
username: EscapedString
password: Optional[EscapedString] = ''
email: EscapedString
enabled: Optional[bool] = 1

View File

@ -68,7 +68,6 @@ def generate_grafana_inv() -> object:
def generate_kp_inv(json_data: json, installed_service) -> object:
inv = {"server": {"hosts": {}}}
server_ips = []
print(json_data)
cluster_id = int(json_data['cluster_id'])
haproxy = json_data['services']['haproxy']['enabled']
nginx = json_data['services']['nginx']['enabled']
@ -181,7 +180,7 @@ def generate_service_inv(json_data: ServiceInstall, installed_service: str) -> o
if installed_service == 'nginx' and not os.path.isdir('/var/www/haproxy-wi/app/scripts/ansible/roles/nginxinc.nginx'):
os.system('ansible-galaxy install nginxinc.nginx,0.24.3 -f --roles-path /var/www/haproxy-wi/app/scripts/ansible/roles/')
for k, v in json_data['servers'].items():
for v in json_data['servers']:
server_ip = v['ip']
if installed_service == 'apache':
correct_service_name = service_common.get_correct_apache_service_name(server_ip=server_ip, server_id=None)

View File

@ -1,7 +1,6 @@
import json
import time
from flask import render_template, request, g, jsonify, Response
from flask import render_template, request, g, jsonify
from flask_jwt_extended import jwt_required
from app.routes.server import bp
@ -58,34 +57,26 @@ def check_ssh(server_ip):
@bp.route('/check/server/<int:server_id>')
def check_server(server_id):
def get_check():
while True:
try:
server = server_sql.get_server_by_id(server_id)
except Exception as e:
raise e
result = server_mod.server_is_up(server.ip)
status = {
"status": result,
'name': server.hostname,
'ip': server.ip,
'port': server.port,
'enabled': server.enabled,
'creds_id': server.cred_id,
'group_id': server.group_id,
'firewall': server.firewall_enable,
'slave': server.master,
'type_ip': server.type_ip,
'description': server.description,
'protected': server.protected,
}
yield f'data:{json.dumps(status)}\n\n'
time.sleep(10)
response = Response(get_check(), mimetype="text/event-stream")
response.headers["Cache-Control"] = "no-cache"
response.headers["X-Accel-Buffering"] = "no"
return response
try:
server = server_sql.get_server_by_id(server_id)
except Exception as e:
raise e
result = server_mod.server_is_up(server.ip)
status = {
"status": result,
'name': server.hostname,
'ip': server.ip,
'port': server.port,
'enabled': server.enabled,
'creds_id': server.cred_id,
'group_id': server.group_id,
'firewall': server.firewall_enable,
'slave': server.master,
'type_ip': server.type_ip,
'description': server.description,
'protected': server.protected,
}
return jsonify(status)
@bp.route('/show/if/<server_ip>')

View File

@ -357,60 +357,57 @@ function showServerInfo(id, ip) {
});
}
async function serverIsUp(server_id) {
let random_sleep = getRandomArbitrary(1000, 10000);
await sleep(random_sleep);
const source = new EventSource(`/server/check/server/${server_id}`);
let server_div = $('#server_status-' + server_id);
source.onmessage = function (event) {
let data = JSON.parse(event.data);
if (data.status === 'up') {
server_div.removeClass('serverNone');
server_div.removeClass('serverDown');
server_div.addClass('serverUp');
server_div.attr('title', 'Server is reachable');
} else if (data.status === 'down') {
server_div.removeClass('serverNone');
server_div.removeClass('serverUp');
server_div.addClass('serverDown');
server_div.attr('title', 'Server is unreachable');
} else {
server_div.removeClass('serverDown');
server_div.removeClass('serverUp');
server_div.addClass('serverNone');
server_div.attr('title', 'Cannot get server status');
$.ajax({
url: "/server/check/server/" + server_id,
contentType: "application/json; charset=utf-8",
success: function (data) {
if (data.status === 'up') {
server_div.removeClass('serverNone');
server_div.removeClass('serverDown');
server_div.addClass('serverUp');
server_div.attr('title', 'Server is reachable');
} else if (data.status === 'down') {
server_div.removeClass('serverNone');
server_div.removeClass('serverUp');
server_div.addClass('serverDown');
server_div.attr('title', 'Server is unreachable');
} else {
server_div.removeClass('serverDown');
server_div.removeClass('serverUp');
server_div.addClass('serverNone');
server_div.attr('title', 'Cannot get server status');
}
$('#hostname-' + server_id).val(data.name);
$('#ip-' + server_id).val(data.ip);
$('#port-' + server_id).val(data.port);
$('#desc-' + server_id).val(data.description);
if (data.enabled === 1) {
$('#enable-' + server_id).prop('checked', true);
} else {
$('#enable-' + server_id).prop('checked', false);
}
if (data.protected === 1) {
$('#protected-' + server_id).prop('checked', true);
} else {
$('#protected-' + server_id).prop('checked', false);
}
if (data.type_ip === 1) {
$('#type_ip-' + server_id).prop('checked', true);
} else {
$('#type_ip-' + server_id).prop('checked', false);
}
$('#type_ip-' + server_id).checkboxradio("refresh");
$('#protected-' + server_id).checkboxradio("refresh");
$('#enable-' + server_id).checkboxradio("refresh");
$('#servergroup-' + server_id).val(data.group_id).change();
$('#credentials-' + server_id).val(data.creds_id).change();
$('#slavefor-' + server_id).val(data.slave).change();
$('#servergroup-' + server_id).selectmenu("refresh");
$('#credentials-' + server_id).selectmenu("refresh");
$('#slavefor-' + server_id).selectmenu("refresh");
}
$('#hostname-' + server_id).val(data.name);
$('#ip-' + server_id).val(data.ip);
$('#port-' + server_id).val(data.port);
$('#desc-' + server_id).val(data.description);
if (data.enabled === 1) {
$('#enable-' + server_id).prop('checked', true);
} else {
$('#enable-' + server_id).prop('checked', false);
}
if (data.protected === 1) {
$('#protected-' + server_id).prop('checked', true);
} else {
$('#protected-' + server_id).prop('checked', false);
}
if (data.type_ip === 1) {
$('#type_ip-' + server_id).prop('checked', true);
} else {
$('#type_ip-' + server_id).prop('checked', false);
}
$('#type_ip-' + server_id).checkboxradio("refresh");
$('#protected-' + server_id).checkboxradio("refresh");
$('#enable-' + server_id).checkboxradio("refresh");
$('#servergroup-' + server_id).val(data.group_id).change();
$('#credentials-' + server_id).val(data.creds_id).change();
$('#slavefor-' + server_id).val(data.slave).change();
$('#servergroup-' + server_id).selectmenu("refresh");
$('#credentials-' + server_id).selectmenu("refresh");
$('#slavefor-' + server_id).selectmenu("refresh");
}
source.onerror = function (event) {
source.close();
}
});
}
function openChangeServerServiceDialog(server_id) {
let user_groups_word = translate_div.attr('data-user_groups');

View File

@ -109,9 +109,9 @@ function addUser(dialog_id) {
"username": new_username_div.val(),
"password": password_div.val(),
"email": email_div.val(),
"role": $('#new-role').val(),
"role_id": $('#new-role').val(),
"enabled": enabled,
"user_group": user_group,
"group_id": user_group,
}
$.ajax({
url: "/user",

View File

@ -430,10 +430,9 @@ function showUploadConfig() {
}
function showListOfVersion(for_delver) {
let cur_url = window.location.href.split('/').pop();
cur_url = cur_url.split('/');
let service = $('#service').val();
let serv = $("#serv").val();
let configver = cur_url[4];
let configver = cur_url;
clearAllAjaxFields();
$.ajax( {
url: "/config/version/" + service + "/list",

View File

@ -7,7 +7,6 @@
<td>
<input type="text" id="{{receiver}}-chanel-{{channel.id}}" class="form-control" value="{{channel.chanel_name}}" size="30">
</td>
{{ g.user_params['role'] }}
{% if g.user_params['role'] == 1 %}
<td>
<select id="{{receiver}}group-{{channel.id}}" name="{{receiver}}group-{{channel.id}}">

View File

@ -174,8 +174,9 @@
});
</script>
{% endif %}
{#<script>#}
{# {%- for server in servers %}#}
{# serverIsUp('{{server.0}}');#}
{# {%- endfor %}#}
{#</script>#}
<script>
{%- for server in servers %}
setInterval(serverIsUp, 18000, '{{server.0}}');
serverIsUp('{{server.0}}');
{%- endfor %}
</script>

View File

@ -35,7 +35,8 @@ class UserView(MethodView):
"""
self.is_api = is_api
def get(self, user_id: int):
@staticmethod
def get(user_id: int):
"""
Get User information by ID
---
@ -54,47 +55,33 @@ class UserView(MethodView):
type: 'object'
id: 'User'
properties:
user_group_id:
type: 'object'
properties:
description:
type: 'string'
description: 'Group description'
group_id:
type: 'integer'
description: 'Group ID'
name:
type: 'string'
description: 'Group name'
group_id:
type: 'integer'
user_id:
type: 'object'
properties:
email:
type: 'string'
description: 'User email'
enabled:
type: 'integer'
description: 'User activation status'
last_login_date:
type: 'string'
format: 'date-time'
description: 'User last login date'
last_login_ip:
type: 'string'
description: 'User last login IP'
ldap_user:
type: 'integer'
description: 'Is User a LDAP user'
role:
type: 'string'
description: 'User role'
user_id:
type: 'integer'
description: 'User ID'
username:
type: 'string'
description: 'Username'
user_role_id:
type: 'integer'
email:
type: 'string'
description: 'User email'
enabled:
type: 'integer'
description: 'User activation status'
last_login_date:
type: 'string'
format: 'date-time'
description: 'User last login date'
last_login_ip:
type: 'string'
description: 'User last login IP'
ldap_user:
type: 'integer'
description: 'Is User a LDAP user'
role_id:
type: 'integer'
description: 'User role'
username:
type: 'string'
description: 'Username'
role_id:
type: 'integer'
description: 'User role ID'
'404':
@ -106,9 +93,8 @@ class UserView(MethodView):
type: 'string'
description: 'Error message'
"""
users_list = []
try:
users = user_sql.select_user_groups_with_names(user_id)
user = user_sql.get_user_id(user_id)
except Exception as e:
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get user')
@ -116,9 +102,7 @@ class UserView(MethodView):
roxywi_common.is_user_has_access_to_its_group(user_id)
except Exception as e:
return roxywi_common.handle_json_exceptions(e, 'Cannot find user'), 404
for user in users:
users_list.append(model_to_dict(user, exclude={User_DB.group_id, User_DB.password, User_DB.user_services}))
return jsonify(users_list)
return jsonify(model_to_dict(user, exclude={User_DB.password, User_DB.user_services}))
@validate(body=UserPost)
def post(self, body: UserPost) -> Union[dict, tuple]:
@ -135,10 +119,8 @@ class UserView(MethodView):
required:
- email
- password
- role
- username
- enabled
- user_group
properties:
email:
type: string
@ -146,7 +128,7 @@ class UserView(MethodView):
password:
type: string
description: The password of the user
role:
role_id:
type: integer
description: The role of the user
username:
@ -171,10 +153,10 @@ class UserView(MethodView):
type: integer
description: The ID of the created user
"""
if g.user_params['role'] > body.role:
if g.user_params['role'] > body.role_id:
return roxywi_common.handle_json_exceptions('Wrong role', 'Cannot create user')
try:
user_id = roxywi_user.create_user(body.username, body.email, body.password, body.role, body.enabled, body.user_group)
user_id = roxywi_user.create_user(body.username, body.email, body.password, body.role_id, body.enabled, body.group_id)
except Exception as e:
return roxywi_common.handle_json_exceptions(e, 'Cannot create a new user')
else:
@ -218,6 +200,9 @@ class UserView(MethodView):
username:
type: string
description: The username of the user
password:
type: string
description: The password of the user
enabled:
type: integer
description: 'Enable status (1 for enabled)'
@ -232,7 +217,8 @@ class UserView(MethodView):
except Exception as e:
return roxywi_common.handle_json_exceptions(e, 'Cannot get user'), 404
try:
user_sql.update_user_from_admin_area(user_id, **body.model_dump(mode='json'))
user_sql.update_user_from_admin_area(user_id, **body.model_dump(mode='json', exclude={'password'}))
user_sql.update_user_password(body.password, user_id)
except Exception as e:
return roxywi_common.handle_json_exceptions(e, 'Cannot update user')
roxywi_common.logging(body.username, 'has been updated user', roxywi=1, login=1)
@ -269,7 +255,7 @@ class UserView(MethodView):
except Exception as e:
return roxywi_common.handle_json_exceptions(e, 'Cannot get user'), 404
if g.user_params['role'] > int(user.role):
if g.user_params['role'] > int(user.role_id):
return roxywi_common.handle_json_exceptions('Wrong role', 'Cannot delete user'), 404
try:
@ -480,7 +466,10 @@ class UserGroupView(MethodView):
'404':
description: 'User or Group not found'
"""
page_for_admin(level=2)
try:
roxywi_auth.page_for_admin(level=2)
except Exception as e:
return roxywi_common.handle_json_exceptions(e, 'Cannot get user or group'), 404
try:
self._check_is_user_and_group(user_id, group_id)
except Exception as e: