from flask_swagger import swagger from flask import jsonify, render_template, abort from flask_pydantic import validate from app import app, jwt from app.api.routes import bp from app.views.install.views import InstallView from app.views.server.views import ( ServerView, CredView, CredsView, ServerGroupView, ServerGroupsView, ServersView, ServerIPView ) from app.views.server.backup_vews import BackupView, S3BackupView from app.views.service.views import ServiceView, ServiceActionView, ServiceBackendView, ServiceConfigView, ServiceConfigVersionsView from app.views.ha.views import HAView, HAVIPView, HAVIPsView from app.views.user.views import UserView, UserGroupView, UserRoles from app.views.udp.views import UDPListener, UDPListeners, UDPListenerActionView from app.views.channel.views import ChannelView, ChannelsView from app.views.tools.views import CheckerView from app.views.admin.views import SettingsView from app.modules.roxywi.class_models import LoginRequest import app.modules.roxywi.auth as roxywi_auth import app.modules.roxywi.common as roxywi_common @bp.before_request def before_request(): """ Protect all the API endpoints. """ user_subscription = roxywi_common.return_user_subscription() if user_subscription['user_status'] == 0 or user_subscription['user_plan'] == 'user': abort(403, 'Your subscription is not active or you are on a Home plan.') pass @jwt.expired_token_loader def my_expired_token_callback(jwt_header, jwt_payload): return jsonify(error="Token is expired"), 401 @jwt.unauthorized_loader def custom_unauthorized_response(_err): return jsonify(error="Authorize first"), 401 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=['POST']) bp.add_url_rule(f'{url}/<{pk_type}:{pk}>', view_func=view_func, methods=['GET', 'PUT', 'DELETE']) def register_api_id_ip(view, endpoint, url: str = '', methods: list = ['GET', 'POST']): for point in ('_id', '_ip'): view_func = view.as_view(f'{endpoint}_{point}') pk = 'int:' if point == '_id' else '' bp.add_url_rule(f'/service//<{pk}server_id>{url}', view_func=view_func, methods=methods) register_api(HAView, 'ha_cluster', '/ha/', 'cluster_id') register_api(UDPListener, 'udp_listener', '//listener', 'listener_id') bp.add_url_rule('//listener//', view_func=UDPListenerActionView.as_view('listener_action'), methods=['GET']) bp.add_url_rule('//listeners', view_func=UDPListeners.as_view('listeners'), methods=['GET']) bp.add_url_rule('/ha///vip/', view_func=HAVIPView.as_view('ha_vip_g'), methods=['GET']) bp.add_url_rule('/ha///vip', view_func=HAVIPView.as_view('ha_vip'), methods=['POST', 'PUT']) bp.add_url_rule('/ha///vip', view_func=HAVIPView.as_view('ha_vip_d'), methods=['DELETE']) bp.add_url_rule('/ha///vips', view_func=HAVIPsView.as_view('ha_vips'), methods=['GET']) register_api_id_ip(ServiceView, 'service', '/status', ['GET']) register_api_id_ip(ServiceBackendView, 'service_backend', '/backend', ['GET']) register_api_id_ip(ServiceConfigView, 'config_view') register_api_id_ip(ServiceConfigVersionsView, 'config_version', '/versions', methods=['GET']) register_api_id_ip(CheckerView, 'checker', '/tools') register_api_id_ip(InstallView, 'install', '/install', methods=['POST']) register_api_id_ip(ServiceActionView, 'service_action', '/', methods=['GET']) register_api(ServerView, 'server', '/server', 'server_id') register_api(BackupView, 'backup_fs', '/server/backup/fs', 'backup_id') register_api(S3BackupView, 'backup_s3', '/server/backup/s3', 'backup_id') bp.add_url_rule('/server//ip', view_func=ServerIPView.as_view('server_ip_ip'), methods=['GET']) bp.add_url_rule('/server//ip', view_func=ServerIPView.as_view('server_ip'), methods=['GET']) register_api(CredView, 'cred', '/server/cred', 'creds_id') bp.add_url_rule('/server/creds', view_func=CredsView.as_view('creds'), methods=['GET']) bp.add_url_rule('/servers', view_func=ServersView.as_view('servers'), methods=['GET']) register_api(ServerGroupView, 'group', '/group', 'group_id') bp.add_url_rule('/groups', view_func=ServerGroupsView.as_view('groups'), methods=['GET']) def register_api_with_group(view, endpoint, url_beg, url_end, pk='user_id', pk_type='int', pk_end='group_id', pk_type_end='int'): view_func = view.as_view(endpoint) bp.add_url_rule(f'/{url_beg}/<{pk_type}:{pk}>/{url_end}', view_func=view_func, methods=['GET']) bp.add_url_rule(f'/{url_beg}/<{pk_type}:{pk}>/{url_end}/<{pk_type_end}:{pk_end}>', view_func=view_func, methods=['PUT', 'DELETE', 'POST', 'PATCH']) register_api(UserView, 'user', '/user', 'user_id') 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_func = view.as_view(endpoint, True) bp.add_url_rule(f'/{url_beg}/', view_func=view_func, methods=['POST']) bp.add_url_rule(f'/{url_beg}//<{pk_type_end}:{pk_end}>', view_func=view_func, methods=['PUT', 'DELETE', 'GET', 'PATCH']) register_api_channel(ChannelView, 'channel', '/channel') bp.add_url_rule('/channels/', view_func=ChannelsView.as_view('channels'), methods=['GET']) bp.add_url_rule( '/settings', view_func=SettingsView.as_view('settings'), methods=['GET'], defaults={'section': None} ) bp.add_url_rule( '/settings/', view_func=SettingsView.as_view('settings_section'), methods=['GET', 'POST'] ) @bp.route("/spec") def spec(): swag = swagger(app) swag['info']['version'] = "1.0" swag['info']['title'] = "Roxy-WI API" return jsonify(swag) @bp.route("/swagger") def swagger_ui(): return render_template('swagger.html') @bp.post('/login') @validate(body=LoginRequest) def do_login(body: LoginRequest): """ Do log in --- tags: - Authentication description: This route is used to log into the system parameters: - name: body in: body schema: type: object properties: login: type: string required: true description: The user's login name password: type: string required: true description: The user's password responses: 200: description: Login successfully, return a JWT token schema: type: object properties: access_token: type: string description: JWT token for user authentication 401: description: Authentication Error """ try: login = body.login password = body.password except Exception as e: return roxywi_common.handler_exceptions_for_json_data(e, 'There is no login or password') try: user_params = roxywi_auth.check_user_password(login, password) except Exception as e: return roxywi_common.handle_json_exceptions(e, ''), 401 access_token = roxywi_auth.create_jwt_token(user_params) return jsonify(access_token=access_token)