mirror of https://github.com/Aidaho12/haproxy-wi
parent
8f50e1b8bf
commit
178116b9c1
|
@ -0,0 +1,255 @@
|
|||
import re
|
||||
from annotated_types import Gt, Le
|
||||
from typing import Optional, Annotated, Union, Literal, Any, Dict, List
|
||||
|
||||
from shlex import quote
|
||||
from pydantic_core import CoreSchema, core_schema
|
||||
from pydantic import BaseModel, field_validator, StringConstraints, IPvAnyAddress, AnyUrl, root_validator, GetCoreSchemaHandler
|
||||
|
||||
DomainName = Annotated[str, StringConstraints(pattern=r"^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z][a-z0-9-]{0,61}[a-z0-9]$")]
|
||||
|
||||
|
||||
class EscapedString(str):
|
||||
pattern = re.compile('[&;|$`]')
|
||||
|
||||
@classmethod
|
||||
def validate(cls, field_value, info) -> str:
|
||||
if isinstance(field_value, str):
|
||||
if cls.pattern.search(field_value):
|
||||
return re.sub(cls.pattern, '', field_value)
|
||||
elif field_value == '':
|
||||
return field_value
|
||||
else:
|
||||
return quote(field_value.rstrip())
|
||||
|
||||
@classmethod
|
||||
def __get_pydantic_core_schema__(
|
||||
cls, source_type: Any, handler: GetCoreSchemaHandler
|
||||
) -> CoreSchema:
|
||||
|
||||
return core_schema.chain_schema(
|
||||
[
|
||||
core_schema.with_info_plain_validator_function(
|
||||
function=cls.validate,
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class BaseResponse(BaseModel):
|
||||
status: str = 'Ok'
|
||||
|
||||
|
||||
class IdResponse(BaseResponse):
|
||||
id: int
|
||||
|
||||
|
||||
class IdDataResponse(IdResponse):
|
||||
data: str
|
||||
|
||||
|
||||
class DataResponse(BaseModel):
|
||||
data: Union[list, dict]
|
||||
|
||||
|
||||
class DataStrResponse(BaseModel):
|
||||
data: str
|
||||
|
||||
|
||||
class ErrorResponse(BaseModel):
|
||||
status: str = 'failed'
|
||||
error: Union[str, list]
|
||||
|
||||
|
||||
class UdpBackendConfig(BaseModel):
|
||||
backend_ip: Union[IPvAnyAddress, DomainName]
|
||||
port: Annotated[int, Gt(1), Le(65535)]
|
||||
weight: Annotated[int, Gt(0), Le(51)]
|
||||
|
||||
|
||||
class UdpListenerRequest(BaseModel):
|
||||
name: EscapedString
|
||||
cluster_id: Optional[int] = None
|
||||
server_id: Optional[int] = None
|
||||
vip: Optional[str] = None
|
||||
port: Annotated[int, Gt(1), Le(65535)]
|
||||
group_id: int
|
||||
config: List[UdpBackendConfig]
|
||||
description: Optional[EscapedString] = None
|
||||
lb_algo: Literal['rr', 'wrr', 'lc', 'wlc', 'sh', 'dh', 'wlc', 'lblc']
|
||||
check_enabled: Optional[bool] = 1
|
||||
reconfigure: Optional[bool] = 0
|
||||
|
||||
|
||||
class UserPost(BaseModel):
|
||||
username: EscapedString
|
||||
password: str
|
||||
email: EscapedString
|
||||
enabled: Optional[bool] = 1
|
||||
user_group: int
|
||||
role: Annotated[int, Gt(0), Le(4)] = 4
|
||||
|
||||
|
||||
class UserPut(BaseModel):
|
||||
username: EscapedString
|
||||
email: EscapedString
|
||||
enabled: Optional[bool] = 1
|
||||
|
||||
|
||||
class AddUserToGroup(BaseModel):
|
||||
role_id: Annotated[int, Gt(0), Le(4)]
|
||||
|
||||
|
||||
class ServerRequest(BaseModel):
|
||||
hostname: EscapedString
|
||||
ip: Union[IPvAnyAddress, DomainName]
|
||||
enabled: Optional[bool] = 1
|
||||
type_ip: Optional[bool] = 0
|
||||
cred_id: int
|
||||
description: Optional[EscapedString] = None
|
||||
group_id: Optional[int] = None
|
||||
protected: Optional[bool] = 0
|
||||
master: Optional[int] = None
|
||||
port: Annotated[int, Gt(1), Le(65535)] = 22
|
||||
haproxy: Optional[bool] = 0
|
||||
nginx: Optional[bool] = 0
|
||||
apache: Optional[bool] = 0
|
||||
firewall_enable: Optional[bool] = 0
|
||||
scan_server: Optional[bool] = 1
|
||||
|
||||
|
||||
class GroupQuery(BaseModel):
|
||||
group_id: Optional[int] = None
|
||||
|
||||
|
||||
class GroupRequest(BaseModel):
|
||||
name: EscapedString
|
||||
description: Optional[EscapedString] = None
|
||||
|
||||
|
||||
class CredRequest(BaseModel):
|
||||
name: EscapedString
|
||||
username: EscapedString
|
||||
password: Optional[EscapedString] = None
|
||||
key_enabled: Optional[bool] = 1
|
||||
group_id: Optional[int] = None
|
||||
|
||||
|
||||
class CredUploadRequest(BaseModel):
|
||||
private_key: str
|
||||
passphrase: Optional[EscapedString] = None
|
||||
|
||||
|
||||
class HAClusterServer(BaseModel):
|
||||
eth: EscapedString
|
||||
id: int
|
||||
ip: Union[IPvAnyAddress, DomainName]
|
||||
name: EscapedString
|
||||
master: Optional[bool] = 1
|
||||
|
||||
|
||||
class HAClusterService(BaseModel):
|
||||
enabled: Optional[bool] = 0
|
||||
docker: Optional[bool] = 0
|
||||
|
||||
|
||||
class HAClusterVIP(BaseModel):
|
||||
name: EscapedString
|
||||
use_src: Optional[bool] = 1
|
||||
vip: IPvAnyAddress
|
||||
return_master: Optional[bool] = 1
|
||||
virt_server: Optional[bool] = 1
|
||||
router_id: Optional[int] = None
|
||||
servers: Dict[int, HAClusterServer]
|
||||
|
||||
|
||||
class HAClusterRequest(BaseModel):
|
||||
name: EscapedString
|
||||
description: Optional[EscapedString] = None
|
||||
return_master: Optional[bool] = 1
|
||||
servers: List[HAClusterServer]
|
||||
services: Dict[str, HAClusterService]
|
||||
syn_flood: Optional[bool] = 1
|
||||
use_src: Optional[bool] = 1
|
||||
vip: IPvAnyAddress
|
||||
virt_server: Optional[bool] = 1
|
||||
|
||||
|
||||
class ConfigFileNameQuery(BaseModel):
|
||||
file_name: Optional[str] = None
|
||||
version: Optional[str] = None
|
||||
|
||||
|
||||
class ConfigRequest(BaseModel):
|
||||
action: Literal['save', 'test', 'reload', 'restart']
|
||||
file_name: Optional[str] = None
|
||||
config_local_path: Optional[str] = None
|
||||
config: str
|
||||
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
login: EscapedString
|
||||
password: EscapedString
|
||||
|
||||
|
||||
class ChannelRequest(BaseModel):
|
||||
token: EscapedString
|
||||
channel: EscapedString
|
||||
group_id: Optional[int] = None
|
||||
|
||||
|
||||
class ServerInstall(BaseModel):
|
||||
ip: Union[IPvAnyAddress, DomainName]
|
||||
master: Optional[bool] = 0
|
||||
name: EscapedString
|
||||
|
||||
|
||||
class ServiceInstall(BaseModel):
|
||||
cluster_id: Optional[int] = None
|
||||
servers: List[ServerInstall]
|
||||
services: Dict[str, HAClusterService]
|
||||
checker: Optional[bool] = 0
|
||||
metrics: Optional[bool] = 0
|
||||
auto_start: Optional[bool] = 0
|
||||
syn_flood: Optional[bool] = 0
|
||||
|
||||
|
||||
class Checker(BaseModel):
|
||||
server_id: int
|
||||
checker: Optional[bool] = 0
|
||||
metrics: Optional[bool] = 0
|
||||
auto_start: Optional[bool] = 0
|
||||
service: Optional[bool] = 1
|
||||
telegram_id: Optional[int] = 0
|
||||
slack_id: Optional[int] = 0
|
||||
pd_id: Optional[int] = 0
|
||||
mm_id: Optional[int] = 0
|
||||
email: Optional[int] = 1
|
||||
service_alert: Optional[int] = 1
|
||||
backend_alert: Optional[int] = 1
|
||||
maxconn_alert: Optional[int] = 1
|
||||
|
||||
|
||||
class SettingsRequest(BaseModel):
|
||||
param: EscapedString
|
||||
value: EscapedString
|
||||
|
||||
|
||||
class BackupRequest(BaseModel):
|
||||
cred_id: int
|
||||
server: Union[IPvAnyAddress, DomainName]
|
||||
rserver: Optional[Union[IPvAnyAddress, DomainName]] = None
|
||||
description: Optional[EscapedString] = None
|
||||
rpath: Optional[EscapedString] = None
|
||||
type: Optional[EscapedString] = None
|
||||
time: Optional[EscapedString] = None
|
||||
|
||||
|
||||
class S3BackupRequest(BaseModel):
|
||||
server: Union[IPvAnyAddress, DomainName]
|
||||
s3_server: Optional[Union[IPvAnyAddress, DomainName]] = None
|
||||
bucket: EscapedString
|
||||
secret_key: Optional[EscapedString] = None
|
||||
access_key: Optional[EscapedString] = None
|
||||
time: Optional[EscapedString] = None
|
||||
description: Optional[EscapedString] = None
|
|
@ -0,0 +1,33 @@
|
|||
class RoxywiGroupMismatch(Exception):
|
||||
""" Raised when not superAdmin tris update resource not from its group. """
|
||||
|
||||
def __init__(self):
|
||||
super(RoxywiGroupMismatch, self).__init__('Group ID does not match')
|
||||
|
||||
|
||||
class RoxywiGroupNotFound(Exception):
|
||||
""" Raised when a group not found. """
|
||||
|
||||
def __init__(self):
|
||||
super(RoxywiGroupNotFound, self).__init__('Group not found')
|
||||
|
||||
|
||||
class RoxywiResourceNotFound(Exception):
|
||||
""" This class represents an exception raised when a resource is not found. """
|
||||
|
||||
def __init__(self, message='Resource not found'):
|
||||
super(RoxywiResourceNotFound, self).__init__(message)
|
||||
|
||||
|
||||
class RoxywiCheckLimits(Exception):
|
||||
""" This class represents an exception raised when a check limit is exceeded. """
|
||||
|
||||
def __init__(self, message='You have reached limit for Free plan'):
|
||||
super(RoxywiCheckLimits, self).__init__(message)
|
||||
|
||||
|
||||
class RoxywiValidationError(Exception):
|
||||
""" This class represents an exception raised when a validation error occurs. """
|
||||
|
||||
def __init__(self, message='Validation error'):
|
||||
super(RoxywiValidationError, self).__init__(message)
|
|
@ -3,7 +3,6 @@ from flask_jwt_extended import jwt_required
|
|||
|
||||
from app.routes.channel import bp
|
||||
from app.middleware import get_user_params
|
||||
import app.modules.common.common as common
|
||||
import app.modules.tools.alerting as alerting
|
||||
import app.modules.roxywi.common as roxywi_common
|
||||
from app.views.channel.views import ChannelView
|
||||
|
@ -42,17 +41,6 @@ def load_channels():
|
|||
return f'{e}'
|
||||
|
||||
|
||||
# @bp.route('/check/<int:channel_id>/<receiver_name>')
|
||||
# def check_receiver(channel_id, receiver_name):
|
||||
# receiver_name = common.checkAjaxInput(receiver_name)
|
||||
#
|
||||
# try:
|
||||
# alerting.check_receiver(channel_id, receiver_name)
|
||||
# return jsonify({'status': 'success'})
|
||||
# except Exception as e:
|
||||
# return roxywi_common.handle_json_exceptions(e, f'Cannot send message via {receiver_name}')
|
||||
|
||||
|
||||
@bp.post('/check')
|
||||
def check_sender():
|
||||
json_data = request.get_json()
|
||||
|
|
|
@ -136,45 +136,6 @@ def config(service, serv, edit, config_file_name, new):
|
|||
return render_template('config.html', **kwargs)
|
||||
|
||||
|
||||
# @bp.route('/<service>/<server_ip>/save', methods=['POST'])
|
||||
# @check_services
|
||||
# @get_user_params()
|
||||
# def save_config(service, server_ip):
|
||||
# roxywi_common.check_is_server_in_group(server_ip)
|
||||
# config_file = request.form.get('config')
|
||||
# oldcfg = request.form.get('oldconfig')
|
||||
# save = request.form.get('save')
|
||||
# config_file_name = request.form.get('config_file_name')
|
||||
#
|
||||
# try:
|
||||
# cfg = config_mod.return_cfg(service, server_ip, config_file_name)
|
||||
# except Exception as e:
|
||||
# return f'error: Cannot get config {e}'
|
||||
#
|
||||
# try:
|
||||
# with open(cfg, "a") as conf:
|
||||
# conf.write(config_file)
|
||||
# except IOError as e:
|
||||
# return f"error: Cannot read imported config file: {e}", 200
|
||||
#
|
||||
# try:
|
||||
# if service == 'keepalived':
|
||||
# stderr = config_mod.upload_and_restart(server_ip, cfg, save, service, oldcfg=oldcfg)
|
||||
# else:
|
||||
# stderr = config_mod.master_slave_upload_and_restart(server_ip, cfg, save, service, oldcfg=oldcfg,
|
||||
# config_file_name=config_file_name)
|
||||
# except Exception as e:
|
||||
# return f'error: {e}', 200
|
||||
#
|
||||
# if save != 'test':
|
||||
# config_mod.diff_config(oldcfg, cfg)
|
||||
#
|
||||
# if stderr:
|
||||
# return stderr, 200
|
||||
#
|
||||
# return
|
||||
|
||||
|
||||
@bp.route('/versions/<service>', defaults={'server_ip': None}, methods=['GET', 'POST'])
|
||||
@bp.route('/versions/<service>/<server_ip>', methods=['GET', 'POST'])
|
||||
@check_services
|
||||
|
|
|
@ -9,20 +9,9 @@ import app.modules.db.service as service_sql
|
|||
import app.modules.server.server as server_mod
|
||||
import app.modules.roxywi.common as roxywi_common
|
||||
import app.modules.service.keepalived as keepalived
|
||||
from app.views.ha.views import HAView, HAVIPView, HAVIPsView
|
||||
from app.views.ha.views import HAView
|
||||
|
||||
|
||||
# def register_api(view, endpoint, url, pk='listener_id', pk_type='int'):
|
||||
# view_func = view.as_view(endpoint)
|
||||
# bp.add_url_rule(url, view_func=view_func, methods=['GET'], defaults={pk: None})
|
||||
# bp.add_url_rule(url, view_func=view_func, methods=['POST'])
|
||||
# bp.add_url_rule(f'{url}/<{pk_type}:{pk}>', view_func=view_func, methods=['GET', 'PUT', 'DELETE'])
|
||||
|
||||
# register_api(HAView, 'ha_cluster', '/<service>', 'cluster_id')
|
||||
# bp.add_url_rule('/<service>/<int:cluster_id>/vip/<int:router_id>', view_func=HAVIPView.as_view('ha_vip_g'), methods=['GET'])
|
||||
bp.add_url_rule('/<service>', view_func=HAView.as_view('ha_cluster'), methods=['GET'], defaults={'cluster_id': None})
|
||||
# bp.add_url_rule('/<service>/<int:router_id>/vip', view_func=HAVIPView.as_view('ha_vip_d'), methods=['DELETE'])
|
||||
# bp.add_url_rule('/<service>/<int:cluster_id>/vips', view_func=HAVIPsView.as_view('ha_vips'), methods=['GET'])
|
||||
|
||||
|
||||
@bp.before_request
|
||||
|
|
|
@ -45,16 +45,6 @@ def install_monitoring():
|
|||
return render_template('install.html', **kwargs)
|
||||
|
||||
|
||||
# @bp.post('/<service>')
|
||||
# @check_services
|
||||
# def install_service(service):
|
||||
# json_data = request.get_json()
|
||||
# try:
|
||||
# return service_mod.install_service(service, json_data)
|
||||
# except Exception as e:
|
||||
# return jsonify({'status': 'failed', 'error': f'{e}'})
|
||||
|
||||
|
||||
@bp.post('/exporter/<exporter>')
|
||||
def install_exporter(exporter):
|
||||
json_data = request.get_json()
|
||||
|
@ -141,14 +131,3 @@ def check_geoip(service, server_ip):
|
|||
service_dir = common.return_nice_path(sql.get_setting(f'{service}_dir'))
|
||||
cmd = f"ls {service_dir}geoip/"
|
||||
return server_mod.ssh_command(server_ip, cmd)
|
||||
|
||||
#
|
||||
# @bp.post('/udp')
|
||||
# def install_udp():
|
||||
# json_data = request.get_json()
|
||||
# listener_id = int(json_data['listener_id'])
|
||||
# try:
|
||||
# inv, server_ips = service_mod.generate_udp_inv(listener_id, 'install')
|
||||
# return service_mod.run_ansible(inv, server_ips, 'udp'), 201
|
||||
# except Exception as e:
|
||||
# return jsonify({'status': 'failed', 'error': f'Cannot create listener: {e}'})
|
||||
|
|
|
@ -156,24 +156,6 @@ def load_backup():
|
|||
return render_template('include/admin_backup.html', **kwargs)
|
||||
|
||||
|
||||
# @bp.post('/s3backup/create')
|
||||
# @bp.post('/s3backup/delete')
|
||||
# def create_s3_backup():
|
||||
# server = common.is_ip_or_dns(request.form.get('s3_backup_server'))
|
||||
# s3_server = common.checkAjaxInput(request.form.get('s3_server'))
|
||||
# bucket = common.checkAjaxInput(request.form.get('s3_bucket'))
|
||||
# secret_key = common.checkAjaxInput(request.form.get('s3_secret_key'))
|
||||
# access_key = common.checkAjaxInput(request.form.get('s3_access_key'))
|
||||
# time = common.checkAjaxInput(request.form.get('time'))
|
||||
# deljob = common.checkAjaxInput(request.form.get('dels3job'))
|
||||
# description = common.checkAjaxInput(request.form.get('description'))
|
||||
#
|
||||
# try:
|
||||
# return backup_mod.s3_backup(server, s3_server, bucket, secret_key, access_key, time, deljob, description)
|
||||
# except Exception as e:
|
||||
# return str(e)
|
||||
|
||||
|
||||
@bp.route('/git', methods=['DELETE', 'POST'])
|
||||
def create_git_backup():
|
||||
json_data = request.get_json()
|
||||
|
|
|
@ -185,24 +185,6 @@ def services(service, serv):
|
|||
return render_template('service.html', **kwargs)
|
||||
|
||||
|
||||
# @bp.post('/action/<service>/check-service')
|
||||
# def check_service(service):
|
||||
# claims = get_jwt()
|
||||
# server_ip = common.checkAjaxInput(request.form.get('server_ip'))
|
||||
#
|
||||
# try:
|
||||
# return service_action.check_service(server_ip, claims['user_id'], service)
|
||||
# except Exception:
|
||||
# return 'logout'
|
||||
#
|
||||
#
|
||||
# @bp.route('/action/<service>/<server_ip>/<action>', methods=['GET'])
|
||||
# def action_service(service, server_ip, action):
|
||||
# server_ip = common.is_ip_or_dns(server_ip)
|
||||
#
|
||||
# return service_action.common_action(server_ip, action, service)
|
||||
|
||||
|
||||
@bp.route('/<service>/<server_ip>/last-edit')
|
||||
@check_services
|
||||
def last_edit(service, server_ip):
|
||||
|
@ -277,27 +259,12 @@ def show_keepalived_become_master():
|
|||
server_ip = common.is_ip_or_dns(request.form.get('keepalivedBecameMaster'))
|
||||
|
||||
return roxy_overview.keepalived_became_master(server_ip)
|
||||
#
|
||||
#
|
||||
# @bp.route('/<service>/backends/<server_ip>')
|
||||
# @cache.cached()
|
||||
# def show_service_backends(service, server_ip):
|
||||
# server_ip = common.is_ip_or_dns(server_ip)
|
||||
#
|
||||
# return service_common.overview_backends(server_ip, service)
|
||||
|
||||
|
||||
@bp.route('/position/<int:server_id>/<int:pos>')
|
||||
def change_pos(server_id, pos):
|
||||
return server_sql.update_server_pos(pos, server_id)
|
||||
|
||||
#
|
||||
# @bp.route('/haproxy/version/<server_ip>')
|
||||
# def get_haproxy_v(server_ip):
|
||||
# server_ip = common.is_ip_or_dns(server_ip)
|
||||
#
|
||||
# return service_common.check_haproxy_version(server_ip)
|
||||
|
||||
|
||||
@bp.route('/settings/<service>/<int:server_id>')
|
||||
@check_services
|
||||
|
|
|
@ -34,56 +34,6 @@ def before_request():
|
|||
pass
|
||||
|
||||
|
||||
# @bp.route('', methods=['POST', 'PUT', 'DELETE'])
|
||||
# @get_user_params()
|
||||
# def create_user():
|
||||
# roxywi_auth.page_for_admin(level=2)
|
||||
# json_data = request.get_json()
|
||||
#
|
||||
# if request.method == 'POST':
|
||||
# email = common.checkAjaxInput(json_data['email'])
|
||||
# password = common.checkAjaxInput(json_data['password'])
|
||||
# role = int(json_data['role'])
|
||||
# new_user = common.checkAjaxInput(json_data['username'])
|
||||
# enabled = int(json_data['enabled'])
|
||||
# group_id = int(json_data['user_group'])
|
||||
# lang = roxywi_common.get_user_lang_for_flask()
|
||||
# current_user_role_id = g.user_params['role']
|
||||
# if not roxywi_common.check_user_group_for_flask():
|
||||
# return roxywi_common.handle_json_exceptions('Wrong group', 'Roxy-WI server', '')
|
||||
# if current_user_role_id > role:
|
||||
# return roxywi_common.handle_json_exceptions('Wrong role', 'Roxy-WI server', '')
|
||||
# try:
|
||||
# user_id = roxywi_user.create_user(new_user, email, password, role, enabled, group_id)
|
||||
# except Exception as e:
|
||||
# return roxywi_common.handle_json_exceptions(e, 'Cannot create a new user')
|
||||
# else:
|
||||
# return jsonify({'status': 'created', 'id': user_id, 'data': render_template(
|
||||
# 'ajax/new_user.html', users=user_sql.select_users(user=new_user), groups=group_sql.select_groups(),
|
||||
# roles=sql.select_roles(), adding=1, lang=lang
|
||||
# )})
|
||||
# elif request.method == 'PUT':
|
||||
# user_id = int(json_data['user_id'])
|
||||
# user_name = common.checkAjaxInput(json_data['username'])
|
||||
# email = common.checkAjaxInput(json_data['email'])
|
||||
# enabled = int(json_data['enabled'])
|
||||
# if roxywi_common.check_user_group_for_flask():
|
||||
# try:
|
||||
# user_sql.update_user_from_admin_area(user_name, email, user_id, enabled)
|
||||
# except Exception as e:
|
||||
# return roxywi_common.handle_json_exceptions(e, 'Cannot update user')
|
||||
# roxywi_common.logging(user_name, ' has been updated user ', roxywi=1, login=1)
|
||||
# return jsonify({'status': 'updated'})
|
||||
# elif request.method == 'DELETE':
|
||||
# roxywi_auth.page_for_admin(level=2)
|
||||
# user_id = int(json_data['user_id'])
|
||||
# try:
|
||||
# roxywi_user.delete_user(user_id)
|
||||
# return jsonify({'status': 'deleted'})
|
||||
# except Exception as e:
|
||||
# return roxywi_common.handle_json_exceptions(e, f'Cannot delete the user {user_id}')
|
||||
|
||||
|
||||
@bp.route('/ldap/<username>')
|
||||
def get_ldap_email(username):
|
||||
roxywi_auth.page_for_admin(level=2)
|
||||
|
@ -140,31 +90,14 @@ def get_current_group():
|
|||
group_id = claims['group']
|
||||
user_id = claims['user_id']
|
||||
if request.method == 'GET':
|
||||
# uuid = common.checkAjaxInput(request.cookies.get('uuid'))
|
||||
# group = common.checkAjaxInput(request.cookies.get('group'))
|
||||
return roxywi_user.get_user_active_group(group_id, user_id)
|
||||
elif request.method == 'PUT':
|
||||
# group_id = common.checkAjaxInput(request.form.get('group'))
|
||||
# user_uuid = common.checkAjaxInput(request.form.get('uuid'))
|
||||
|
||||
return roxywi_user.change_user_active_group(group_id, user_id)
|
||||
|
||||
|
||||
# @bp.route('/groups/<int:user_id>')
|
||||
# def show_user_groups_and_roles(user_id):
|
||||
# lang = roxywi_common.get_user_lang_for_flask()
|
||||
#
|
||||
# return roxywi_user.show_user_groups_and_roles(user_id, lang)
|
||||
|
||||
|
||||
@bp.post('/groups/save')
|
||||
def change_user_groups_and_roles():
|
||||
user = common.checkAjaxInput(request.form.get('changeUserGroupsUser'))
|
||||
groups_and_roles = json.loads(request.form.get('jsonDatas'))
|
||||
|
||||
return roxywi_user.save_user_group_and_role(user, groups_and_roles)
|
||||
|
||||
|
||||
# @bp.route('/group/name/<int:group_id>')
|
||||
# def get_group_name_by_id(group_id):
|
||||
# return group_sql.get_group_name_by_id(group_id)
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="SwaggerUI" />
|
||||
<title>SwaggerUI</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js" crossorigin></script>
|
||||
<script src="https://unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-standalone-preset.js" crossorigin></script>
|
||||
<script>
|
||||
window.onload = () => {
|
||||
window.ui = SwaggerUIBundle({
|
||||
url: '{{ url_for('api.spec') }}',
|
||||
dom_id: '#swagger-ui',
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,476 @@
|
|||
from flask import render_template, g, jsonify
|
||||
from flask.views import MethodView
|
||||
from flask_pydantic import validate
|
||||
from flask_jwt_extended import jwt_required
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
|
||||
import app.modules.roxywi.auth as roxywi_auth
|
||||
import app.modules.roxywi.common as roxywi_common
|
||||
import app.modules.common.common as common
|
||||
import app.modules.db.udp as udp_sql
|
||||
import app.modules.db.ha_cluster as ha_sql
|
||||
import app.modules.db.server as server_sql
|
||||
import app.modules.service.udp as udp_mod
|
||||
import app.modules.service.installation as service_mod
|
||||
from app.middleware import get_user_params, check_services, page_for_admin, check_group
|
||||
from app.modules.common.common_classes import SupportClass
|
||||
from app.modules.roxywi.class_models import BaseResponse, IdResponse, UdpListenerRequest, GroupQuery
|
||||
|
||||
|
||||
class UDPListener(MethodView):
|
||||
method_decorators = ["GET", "POST", "PUT", "DELETE"]
|
||||
decorators = [jwt_required(), get_user_params(), check_services, check_group()]
|
||||
|
||||
def __init__(self, is_api=True):
|
||||
self.is_api = is_api
|
||||
|
||||
def get(self, service: str, listener_id: int):
|
||||
"""
|
||||
Get information about a specific UDP listener.
|
||||
---
|
||||
tags:
|
||||
- UDP listener
|
||||
parameters:
|
||||
- name: service
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: 'Can be only "udp"'
|
||||
- name: listener_id
|
||||
in: path
|
||||
type: integer
|
||||
required: true
|
||||
description: The listener's identifier
|
||||
|
||||
responses:
|
||||
200:
|
||||
description: Listener configuration returned successfully
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
check_enabled:
|
||||
type: integer
|
||||
cluster_id:
|
||||
type: string
|
||||
config:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
backend_ip:
|
||||
type: string
|
||||
description: The IP address of the backend server
|
||||
port:
|
||||
type: integer
|
||||
description: Port number on which the backend server listens for requests
|
||||
weight:
|
||||
type: integer
|
||||
description: Weight assigned to the backend server
|
||||
delay_before_retry:
|
||||
type: integer
|
||||
delay_loop:
|
||||
type: integer
|
||||
description:
|
||||
type: string
|
||||
group_id:
|
||||
type: integer
|
||||
id:
|
||||
type: integer
|
||||
lb_algo:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
port:
|
||||
type: integer
|
||||
retry:
|
||||
type: integer
|
||||
server_id:
|
||||
type: integer
|
||||
vip:
|
||||
type: string
|
||||
default:
|
||||
description: Unexpected error
|
||||
"""
|
||||
if self.is_api:
|
||||
if listener_id:
|
||||
try:
|
||||
listener_config = udp_mod.get_listener_config(listener_id)
|
||||
listener_config['status'] = udp_mod.check_is_listener_active(listener_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Listener not found')
|
||||
return jsonify(listener_config)
|
||||
else:
|
||||
if not listener_id:
|
||||
kwargs = {
|
||||
'listeners': udp_sql.select_listeners(g.user_params['group_id']),
|
||||
'lang': g.user_params['lang'],
|
||||
'clusters': ha_sql.select_clusters(g.user_params['group_id']),
|
||||
'is_needed_tool': common.is_tool('ansible'),
|
||||
'user_subscription': roxywi_common.return_user_subscription()
|
||||
}
|
||||
return render_template('udp/listeners.html', **kwargs)
|
||||
else:
|
||||
listener = udp_sql.get_listener(listener_id)
|
||||
cluster = dict()
|
||||
server = dict()
|
||||
if listener.cluster_id:
|
||||
cluster = ha_sql.select_cluster(listener.cluster_id)
|
||||
elif listener.server_id:
|
||||
server = server_sql.get_server_by_id(listener.server_id)
|
||||
kwargs = {
|
||||
'clusters': cluster,
|
||||
'listener': listener,
|
||||
'server': server,
|
||||
'lang': g.user_params['lang'],
|
||||
}
|
||||
return render_template('udp/listener.html', **kwargs)
|
||||
|
||||
@validate(body=UdpListenerRequest)
|
||||
def post(self, service: str, body: UdpListenerRequest):
|
||||
"""
|
||||
This endpoint allows to create a new UDP listener.
|
||||
---
|
||||
tags:
|
||||
- UDP listener
|
||||
parameters:
|
||||
- in: 'path'
|
||||
name: 'service'
|
||||
description: 'Can be only "udp"'
|
||||
required: true
|
||||
schema:
|
||||
type: 'string'
|
||||
- in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
required:
|
||||
- config
|
||||
- name
|
||||
- port
|
||||
- lb_algo
|
||||
- vip
|
||||
type: object
|
||||
properties:
|
||||
config:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
backend_ip:
|
||||
type: string
|
||||
description: The IP address of the backend server
|
||||
port:
|
||||
type: integer
|
||||
description: Port number on which the backend server listens for requests
|
||||
weight:
|
||||
type: integer
|
||||
description: Weight assigned to the backend server
|
||||
name:
|
||||
type: string
|
||||
cluster_id:
|
||||
type: int
|
||||
description: Cluster ID where the UDP listener is located. Must be determined if server_id empty
|
||||
server_id:
|
||||
type: int
|
||||
description: Standalone mode. Server ID where the UDP listener is located. Must be determined if cluster_id empty
|
||||
group_id:
|
||||
type: string
|
||||
port:
|
||||
type: string
|
||||
lb_algo:
|
||||
type: string
|
||||
description: "'rr': 'Round robin', 'wrr': 'Weighted Round Robin', 'lc': 'Least Connection', 'wlc': 'Weighted Least Connection', 'sh': 'Source Hashing', 'dh': 'Destination Hashing', 'lblc': 'Locality-Based Least Connection'"
|
||||
schema:
|
||||
enum: [rr, wrr, lc, wlc, sh, dh, wlc, lblc]
|
||||
description:
|
||||
type: string
|
||||
vip:
|
||||
type: string
|
||||
description: IP address of the UDP listener binding, if Standalone mode. VIP address of the UDP listener binding, if HA Cluster mode
|
||||
reconfigure:
|
||||
type: boolean
|
||||
description: If 1, reconfigure UDP listener. If 0, just save UDP listener without configuration on servers
|
||||
responses:
|
||||
201:
|
||||
description: UDP listener created successfully
|
||||
400:
|
||||
description: Invalid request data
|
||||
default:
|
||||
description: Unexpected error
|
||||
"""
|
||||
roxywi_auth.page_for_admin(level=3)
|
||||
try:
|
||||
listener_id = udp_sql.insert_listener(**body.model_dump(mode='json', exclude={'reconfigure'}))
|
||||
roxywi_common.logging(listener_id, f'UDP listener {body.name} has been created', keep_history=1,
|
||||
roxywi=1, service='UDP Listener')
|
||||
if body.reconfigure:
|
||||
self._reconfigure(listener_id, 'install')
|
||||
return IdResponse(id=listener_id).model_dump(mode='json')
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot create UDP listener')
|
||||
|
||||
@validate(body=UdpListenerRequest)
|
||||
def put(self, service: str, listener_id: int, body: UdpListenerRequest):
|
||||
"""
|
||||
This endpoint allows to update a UDP listener.
|
||||
---
|
||||
tags:
|
||||
- UDP listener
|
||||
parameters:
|
||||
- in: 'path'
|
||||
name: 'service'
|
||||
description: 'Can be only "udp"'
|
||||
required: true
|
||||
schema:
|
||||
type: 'string'
|
||||
- in: 'path'
|
||||
name: 'listener_id'
|
||||
description: 'ID of the UDP listener'
|
||||
required: true
|
||||
schema:
|
||||
type: 'integer'
|
||||
- in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
required:
|
||||
- config
|
||||
- name
|
||||
- port
|
||||
- lb_algo
|
||||
- vip
|
||||
type: object
|
||||
properties:
|
||||
config:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
backend_ip:
|
||||
type: string
|
||||
description: The IP address of the backend server
|
||||
port:
|
||||
type: integer
|
||||
description: Port number on which the backend server listens for requests
|
||||
weight:
|
||||
type: integer
|
||||
description: Weight assigned to the backend server
|
||||
name:
|
||||
type: string
|
||||
cluster_id:
|
||||
type: int
|
||||
description: Cluster ID where the UDP listener is located. Must be determined if server_id empty
|
||||
server_id:
|
||||
type: int
|
||||
description: Standalone mode. Server ID where the UDP listener is located. Must be determined if cluster_id empty
|
||||
group_id:
|
||||
type: string
|
||||
port:
|
||||
type: string
|
||||
lb_algo:
|
||||
type: string
|
||||
description: "'rr': 'Round robin', 'wrr': 'Weighted Round Robin', 'lc': 'Least Connection', 'wlc': 'Weighted Least Connection', 'sh': 'Source Hashing', 'dh': 'Destination Hashing', 'lblc': 'Locality-Based Least Connection'"
|
||||
schema:
|
||||
enum: [rr, wrr, lc, wlc, sh, dh, wlc, lblc]
|
||||
description:
|
||||
type: string
|
||||
vip:
|
||||
type: string
|
||||
description: IP address of the UDP listener binding, if Standalone mode. VIP address of the UDP listener binding, if HA Cluster mode
|
||||
reconfigure:
|
||||
type: boolean
|
||||
description: If 1, reconfigure UDP listener. If 0, just save UDP listener without configuration on servers
|
||||
responses:
|
||||
201:
|
||||
description: UDP listener created successfully
|
||||
400:
|
||||
description: Invalid request data
|
||||
default:
|
||||
description: Unexpected error
|
||||
"""
|
||||
roxywi_auth.page_for_admin(level=3)
|
||||
try:
|
||||
udp_sql.update_listener(listener_id, **body.model_dump(mode='json', exclude={'reconfigure'}))
|
||||
roxywi_common.logging(listener_id, f'UDP listener {body.name} has been updated', keep_history=1,
|
||||
roxywi=1, service='UDP Listener')
|
||||
if body.reconfigure:
|
||||
self._reconfigure(listener_id, 'install')
|
||||
return BaseResponse().model_dump(mode='json')
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot update UDP listener')
|
||||
|
||||
def delete(self, service: str, listener_id: int):
|
||||
"""
|
||||
Delete a UDP listener
|
||||
---
|
||||
tags:
|
||||
- UDP listener
|
||||
parameters:
|
||||
- in: 'path'
|
||||
name: 'service'
|
||||
description: 'Can be only "udp"'
|
||||
required: true
|
||||
schema:
|
||||
type: 'string'
|
||||
- in: 'path'
|
||||
name: 'listener_id'
|
||||
description: 'ID of the UDP listener'
|
||||
required: true
|
||||
schema:
|
||||
type: 'integer'
|
||||
responses:
|
||||
204:
|
||||
description: UDP listener deletion successful
|
||||
"""
|
||||
roxywi_auth.page_for_admin(level=3)
|
||||
try:
|
||||
self._reconfigure(listener_id, 'uninstall')
|
||||
roxywi_common.logging(listener_id, f'UDP listener has been deleted {listener_id}', roxywi=1, keep_history=1, login=1, service='UDP listener')
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e,f'Cannot create inventory for UDP listener deleting {listener_id}')
|
||||
try:
|
||||
udp_sql.delete_listener(listener_id)
|
||||
return BaseResponse().model_dump(mode='json'), 204
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e,f'Cannot delete UDP listener {listener_id}')
|
||||
|
||||
@staticmethod
|
||||
def _reconfigure(listener_id, action):
|
||||
try:
|
||||
inv, server_ips = service_mod.generate_udp_inv(listener_id, action)
|
||||
except Exception as e:
|
||||
raise Exception(e)
|
||||
try:
|
||||
output = service_mod.run_ansible(inv, server_ips, 'udp')
|
||||
if len(output['failures']) > 0 or len(output['dark']) > 0:
|
||||
raise Exception(f'Cannot {action} UDP listener. Check Apache error log')
|
||||
except Exception as e:
|
||||
raise Exception(f'Cannot {action} UDP listener: {e}')
|
||||
|
||||
|
||||
class UDPListeners(MethodView):
|
||||
method_decorators = ["GET"]
|
||||
decorators = [jwt_required(), get_user_params(), check_services, check_group()]
|
||||
|
||||
@validate(query=GroupQuery)
|
||||
def get(self, service: str, query: GroupQuery):
|
||||
"""
|
||||
Get information about a specific UDP listener.
|
||||
---
|
||||
tags:
|
||||
- UDP listener
|
||||
parameters:
|
||||
- name: service
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: 'Can be only "udp"'
|
||||
- name: group_id
|
||||
in: query
|
||||
type: integer
|
||||
required: false
|
||||
description: The group's identifier. Only accessible by superAdmin role.
|
||||
responses:
|
||||
200:
|
||||
description: Listener configuration returned successfully
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
check_enabled:
|
||||
type: integer
|
||||
cluster_id:
|
||||
type: string
|
||||
config:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
backend_ip:
|
||||
type: string
|
||||
description: The IP address of the backend server
|
||||
port:
|
||||
type: integer
|
||||
description: Port number on which the backend server listens for requests
|
||||
weight:
|
||||
type: integer
|
||||
description: Weight assigned to the backend server
|
||||
delay_before_retry:
|
||||
type: integer
|
||||
delay_loop:
|
||||
type: integer
|
||||
description:
|
||||
type: string
|
||||
group_id:
|
||||
type: integer
|
||||
id:
|
||||
type: integer
|
||||
lb_algo:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
port:
|
||||
type: integer
|
||||
retry:
|
||||
type: integer
|
||||
server_id:
|
||||
type: integer
|
||||
vip:
|
||||
type: string
|
||||
default:
|
||||
description: Unexpected error
|
||||
"""
|
||||
try:
|
||||
group_id = SupportClass.return_group_id(query)
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, f'Cannot get UDP listeners')
|
||||
try:
|
||||
listeners = udp_sql.select_listeners(group_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, f'Cannot get UDP listeners')
|
||||
return jsonify([model_to_dict(listener, recurse=False) for listener in listeners])
|
||||
|
||||
|
||||
class UDPListenerActionView(MethodView):
|
||||
methods = ['GET']
|
||||
decorators = [jwt_required(), get_user_params(), check_services, page_for_admin(level=3), check_group()]
|
||||
|
||||
@staticmethod
|
||||
def get(service: str, listener_id: int, action: str):
|
||||
"""
|
||||
This endpoint performs a specified action on a certain UDP listener.
|
||||
---
|
||||
tags:
|
||||
- UDP listener
|
||||
parameters:
|
||||
- in: path
|
||||
name: service
|
||||
required: true
|
||||
description: Can be only "udp"
|
||||
- in: path
|
||||
name: listener_id
|
||||
schema:
|
||||
type: integer
|
||||
required: true
|
||||
description: The ID af the UDP listener
|
||||
- in: path
|
||||
name: action
|
||||
schema:
|
||||
type: string
|
||||
enum: [start, stop, reload, restart]
|
||||
required: true
|
||||
description: The action to be performed on the service (start, stop, reload, restart)
|
||||
responses:
|
||||
200:
|
||||
description: Successful operation
|
||||
default:
|
||||
description: Unexpected error
|
||||
"""
|
||||
try:
|
||||
udp_mod.listener_actions(listener_id, action, g.user_params['group_id'])
|
||||
roxywi_common.logging(listener_id, f'UDP listener {listener_id} has been {action}ed', roxywi=1,
|
||||
keep_history=1, login=1, service='UDP listener')
|
||||
return BaseResponse().model_dump(mode='json')
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, f'Cannot {action} listener')
|
|
@ -0,0 +1,548 @@
|
|||
from typing import Union
|
||||
|
||||
from flask.views import MethodView
|
||||
from flask_pydantic import validate
|
||||
from flask import render_template, jsonify, g
|
||||
from flask_jwt_extended import jwt_required
|
||||
from flask_jwt_extended import set_access_cookies
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
|
||||
import app.modules.db.sql as sql
|
||||
import app.modules.db.user as user_sql
|
||||
import app.modules.db.group as group_sql
|
||||
import app.modules.roxywi.user as roxywi_user
|
||||
import app.modules.roxywi.auth as roxywi_auth
|
||||
import app.modules.roxywi.common as roxywi_common
|
||||
from app.modules.db.db_model import User as User_DB
|
||||
from app.modules.roxywi.class_models import UserPost, UserPut, IdResponse, IdDataResponse, BaseResponse, AddUserToGroup
|
||||
from app.modules.roxywi.exception import RoxywiResourceNotFound
|
||||
from app.middleware import get_user_params, page_for_admin, check_group
|
||||
|
||||
|
||||
class UserView(MethodView):
|
||||
methods = ["GET", "POST", "PUT", "DELETE"]
|
||||
decorators = [jwt_required(), get_user_params(), page_for_admin(level=2), check_group()]
|
||||
|
||||
def __init__(self, is_api=False):
|
||||
"""
|
||||
Initialize UserView instance
|
||||
---
|
||||
parameters:
|
||||
- name: is_api
|
||||
in: path
|
||||
type: boolean
|
||||
description: is api
|
||||
"""
|
||||
self.is_api = is_api
|
||||
|
||||
def get(self, user_id: int):
|
||||
"""
|
||||
Get User information by ID
|
||||
---
|
||||
tags:
|
||||
- 'User'
|
||||
parameters:
|
||||
- in: 'path'
|
||||
name: 'user_id'
|
||||
description: 'ID of the User to retrieve'
|
||||
required: true
|
||||
type: 'integer'
|
||||
responses:
|
||||
'200':
|
||||
description: 'Successful Operation'
|
||||
schema:
|
||||
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'
|
||||
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'
|
||||
description: 'User role ID'
|
||||
'404':
|
||||
description: 'User not found'
|
||||
schema:
|
||||
id: 'NotFound'
|
||||
properties:
|
||||
message:
|
||||
type: 'string'
|
||||
description: 'Error message'
|
||||
"""
|
||||
users_list = []
|
||||
try:
|
||||
users = user_sql.select_user_groups_with_names(user_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot get user')
|
||||
|
||||
try:
|
||||
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)
|
||||
|
||||
@validate(body=UserPost)
|
||||
def post(self, body: UserPost) -> Union[dict, tuple]:
|
||||
"""
|
||||
Create a new user
|
||||
---
|
||||
tags:
|
||||
- User
|
||||
parameters:
|
||||
- name: body
|
||||
in: body
|
||||
schema:
|
||||
id: NewUser
|
||||
required:
|
||||
- email
|
||||
- password
|
||||
- role
|
||||
- username
|
||||
- enabled
|
||||
- user_group
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
description: The email of the user
|
||||
password:
|
||||
type: string
|
||||
description: The password of the user
|
||||
role:
|
||||
type: integer
|
||||
description: The role of the user
|
||||
username:
|
||||
type: string
|
||||
description: The username of the user
|
||||
enabled:
|
||||
type: integer
|
||||
description: 'Enable status (1 for enabled)'
|
||||
group_id:
|
||||
type: integer
|
||||
description: The ID of the user's group
|
||||
responses:
|
||||
200:
|
||||
description: user created
|
||||
schema:
|
||||
id: CreateUserResponse
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
description: The status of the user creation
|
||||
id:
|
||||
type: integer
|
||||
description: The ID of the created user
|
||||
"""
|
||||
if g.user_params['role'] > body.role:
|
||||
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)
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot create a new user')
|
||||
else:
|
||||
if self.is_api:
|
||||
return IdResponse(id=user_id), 201
|
||||
else:
|
||||
lang = roxywi_common.get_user_lang_for_flask()
|
||||
data = render_template(
|
||||
'ajax/new_user.html', users=user_sql.select_users(user=body.username), groups=group_sql.select_groups(),
|
||||
roles=sql.select_roles(), adding=1, lang=lang
|
||||
)
|
||||
return IdDataResponse(id=user_id, data=data), 201
|
||||
|
||||
@validate(body=UserPut)
|
||||
def put(self, user_id: int, body: UserPut) -> Union[dict, tuple]:
|
||||
"""
|
||||
Update User Information
|
||||
---
|
||||
tags:
|
||||
- User
|
||||
description: Update the information of a user based on the provided user ID.
|
||||
parameters:
|
||||
- in: 'path'
|
||||
name: 'user_id'
|
||||
description: 'ID of the User to retrieve'
|
||||
required: true
|
||||
type: 'integer'
|
||||
- in: body
|
||||
name: body
|
||||
schema:
|
||||
id: UserUpdate
|
||||
required:
|
||||
- id
|
||||
- username
|
||||
- email
|
||||
- enabled
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
description: The email of the user
|
||||
username:
|
||||
type: string
|
||||
description: The username of the user
|
||||
enabled:
|
||||
type: integer
|
||||
description: 'Enable status (1 for enabled)'
|
||||
responses:
|
||||
400:
|
||||
description: Invalid request
|
||||
201:
|
||||
description: User information update successful
|
||||
"""
|
||||
try:
|
||||
_ = user_sql.get_user_id(user_id)
|
||||
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'))
|
||||
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)
|
||||
return BaseResponse(), 201
|
||||
|
||||
@validate()
|
||||
def delete(self, user_id: int):
|
||||
"""
|
||||
Delete a User
|
||||
---
|
||||
tags:
|
||||
- User
|
||||
Description: Delete a user based on the provided user ID.
|
||||
parameters:
|
||||
- in: 'path'
|
||||
name: 'user_id'
|
||||
description: 'User ID to delete'
|
||||
required: true
|
||||
type: 'integer'
|
||||
responses:
|
||||
204:
|
||||
description: User deletion successful
|
||||
400:
|
||||
description: Invalid request
|
||||
404:
|
||||
description: User not found
|
||||
"""
|
||||
try:
|
||||
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
|
||||
try:
|
||||
user = user_sql.get_user_id(user_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot get user'), 404
|
||||
|
||||
if g.user_params['role'] > int(user.role):
|
||||
return roxywi_common.handle_json_exceptions('Wrong role', 'Cannot delete user'), 404
|
||||
|
||||
try:
|
||||
roxywi_user.delete_user(user_id)
|
||||
return BaseResponse().model_dump(mode='json'), 204
|
||||
except Exception as e:
|
||||
return roxywi_common.handler_exceptions_for_json_data(e, 'Cannot delete the user')
|
||||
|
||||
|
||||
class UserGroupView(MethodView):
|
||||
methods = ["GET", "POST", "PUT", "DELETE", "PATCH"]
|
||||
decorators = [jwt_required(), get_user_params(), page_for_admin(level=4), check_group()]
|
||||
|
||||
def get(self, user_id: int):
|
||||
"""
|
||||
Fetch a specific User Group.
|
||||
---
|
||||
tags:
|
||||
- User group
|
||||
parameters:
|
||||
- in: 'path'
|
||||
name: 'user_id'
|
||||
description: 'User ID to get'
|
||||
required: true
|
||||
type: 'integer'
|
||||
responses:
|
||||
200:
|
||||
description: A list of user's groups
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
id: UserGet
|
||||
properties:
|
||||
user_group_id:
|
||||
type: integer
|
||||
description: User group ID
|
||||
example: 1
|
||||
user_role_id:
|
||||
type: integer
|
||||
description: User role ID
|
||||
example: 1
|
||||
"""
|
||||
try:
|
||||
users = user_sql.select_user_groups_with_names(user_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot get group')
|
||||
|
||||
json_data = []
|
||||
for user in users:
|
||||
json_data.append(model_to_dict(user, exclude=[User_DB.password, User_DB.user_services]))
|
||||
|
||||
return jsonify(json_data)
|
||||
|
||||
@validate(body=AddUserToGroup)
|
||||
def post(self, user_id: int, group_id: int, body: AddUserToGroup):
|
||||
"""
|
||||
Add a User to a specific Group
|
||||
---
|
||||
tags:
|
||||
- 'User group'
|
||||
parameters:
|
||||
- in: 'path'
|
||||
name: 'user_id'
|
||||
description: 'ID of the User to be added'
|
||||
required: true
|
||||
type: 'integer'
|
||||
- in: 'path'
|
||||
name: 'group_id'
|
||||
description: 'ID of the Group which will have a new user'
|
||||
required: true
|
||||
type: 'integer'
|
||||
- in: body
|
||||
name: role_id
|
||||
required: true
|
||||
schema:
|
||||
properties:
|
||||
role_id:
|
||||
type: integer
|
||||
description: A role inside the group
|
||||
responses:
|
||||
'201':
|
||||
description: 'User successfully added to the group'
|
||||
'404':
|
||||
description: 'User or Group not found'
|
||||
"""
|
||||
page_for_admin(level=2)
|
||||
try:
|
||||
self._check_is_user_and_group(user_id, group_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot get user or group'), 404
|
||||
try:
|
||||
user_sql.update_user_role(user_id, group_id, body.role_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot add user to group'), 500
|
||||
else:
|
||||
return BaseResponse().model_dump(mode='json'), 201
|
||||
|
||||
@validate(body=AddUserToGroup)
|
||||
def put(self, user_id: int, group_id: int, body: AddUserToGroup):
|
||||
"""
|
||||
Update a User to a specific Group
|
||||
---
|
||||
tags:
|
||||
- 'User group'
|
||||
parameters:
|
||||
- in: 'path'
|
||||
name: 'user_id'
|
||||
description: 'ID of the User to be added'
|
||||
required: true
|
||||
type: 'integer'
|
||||
- in: 'path'
|
||||
name: 'group_id'
|
||||
description: 'ID of the Group where updating the user'
|
||||
required: true
|
||||
type: 'integer'
|
||||
- in: body
|
||||
name: role_id
|
||||
required: true
|
||||
schema:
|
||||
properties:
|
||||
role_id:
|
||||
type: integer
|
||||
description: A role inside the group
|
||||
responses:
|
||||
'201':
|
||||
description: 'User successfully added to the group'
|
||||
'404':
|
||||
description: 'User or Group not found'
|
||||
"""
|
||||
page_for_admin(level=2)
|
||||
try:
|
||||
self._check_is_user_and_group(user_id, group_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot get user or group'), 404
|
||||
|
||||
try:
|
||||
user_sql.delete_user_from_group(group_id, user_id)
|
||||
user_sql.update_user_role(user_id, group_id, body.role_id)
|
||||
return BaseResponse().model_dump(mode='json'), 201
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot delete user')
|
||||
|
||||
def patch(self, user_id: int, group_id: int):
|
||||
"""
|
||||
Assign a User to a specific Group
|
||||
---
|
||||
tags:
|
||||
- 'User group'
|
||||
parameters:
|
||||
- in: 'path'
|
||||
name: 'user_id'
|
||||
description: 'ID of the User to be assigned to the group'
|
||||
required: true
|
||||
type: 'integer'
|
||||
- in: 'path'
|
||||
name: 'group_id'
|
||||
description: 'ID of the Group which the user will be assigned to'
|
||||
required: true
|
||||
type: 'integer'
|
||||
responses:
|
||||
201:
|
||||
description: 'User successfully assigned to the group'
|
||||
404:
|
||||
description: 'User or Group not found'
|
||||
schema:
|
||||
id: 'NotFound'
|
||||
properties:
|
||||
error:
|
||||
type: 'string'
|
||||
description: 'Error message'
|
||||
"""
|
||||
try:
|
||||
self._check_is_user_and_group(user_id, group_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot get user or group'), 404
|
||||
|
||||
user_param = {"user": user_id, "group": group_id}
|
||||
access_token = roxywi_auth.create_jwt_token(user_param)
|
||||
response = jsonify({'status': 'Ok'})
|
||||
set_access_cookies(response, access_token)
|
||||
try:
|
||||
user_sql.update_user_current_groups(group_id, user_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot update user or group'), 500
|
||||
return response
|
||||
|
||||
def delete(self, user_id: int, group_id: int):
|
||||
"""
|
||||
Delete a User from a specific Group
|
||||
---
|
||||
tags:
|
||||
- 'User group'
|
||||
parameters:
|
||||
- in: 'path'
|
||||
name: 'user_id'
|
||||
description: 'ID of the User to be deleted'
|
||||
required: true
|
||||
type: 'integer'
|
||||
- in: 'path'
|
||||
name: 'group_id'
|
||||
description: 'ID of the Group from which user will be deleted'
|
||||
required: true
|
||||
type: 'integer'
|
||||
responses:
|
||||
'204':
|
||||
description: 'User successfully deleted'
|
||||
'404':
|
||||
description: 'User or Group not found'
|
||||
"""
|
||||
page_for_admin(level=2)
|
||||
try:
|
||||
self._check_is_user_and_group(user_id, group_id)
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot get user or group'), 404
|
||||
|
||||
try:
|
||||
user_sql.delete_user_from_group(group_id, user_id)
|
||||
return BaseResponse().model_dump(mode='json'), 204
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot delete user')
|
||||
|
||||
@staticmethod
|
||||
def _check_is_user_and_group(user_id: int, group_id: int):
|
||||
try:
|
||||
_ = user_sql.get_user_id(user_id)
|
||||
groups = group_sql.get_group_name_by_id(group_id)
|
||||
if len(groups) == 0:
|
||||
raise RoxywiResourceNotFound
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
|
||||
class UserRoles(MethodView):
|
||||
methods = ['GET']
|
||||
decorators = [jwt_required(), get_user_params(), page_for_admin()]
|
||||
|
||||
@staticmethod
|
||||
def get():
|
||||
"""
|
||||
User Roles
|
||||
---
|
||||
tags:
|
||||
- User Roles
|
||||
summary: Get All User Role Information
|
||||
description: This method is used to retrieve all available user roles along with their descriptions and corresponding role_ids.
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
200:
|
||||
description: User Roles Returned
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: The name of the user role.
|
||||
example: "superAdmin"
|
||||
role_id:
|
||||
type: integer
|
||||
description: The ID of the user role.
|
||||
example: 1
|
||||
description:
|
||||
type: string
|
||||
description: The description of the user role.
|
||||
example: "Has the highest level of administrative..."
|
||||
"""
|
||||
try:
|
||||
roles = sql.select_roles()
|
||||
except Exception as e:
|
||||
return roxywi_common.handle_json_exceptions(e, 'Cannot get roles')
|
||||
roles_list = []
|
||||
for role in roles:
|
||||
roles_list.append(model_to_dict(role))
|
||||
return jsonify(roles_list)
|
Loading…
Reference in New Issue