From 26a62236861cfb1c167307f73a603b085bc7bc32 Mon Sep 17 00:00:00 2001 From: Jiri Kyjovsky Date: Sun, 14 Apr 2024 18:04:31 +0200 Subject: [PATCH] frontend: delete compatibility code between flask and flask-restx --- .../coprs/views/apiv3_ns/__init__.py | 81 +++++------------- .../views/apiv3_ns/apiv3_build_chroots.py | 4 +- .../coprs/views/apiv3_ns/apiv3_builds.py | 36 ++++---- .../coprs/views/apiv3_ns/apiv3_general.py | 4 +- .../coprs/views/apiv3_ns/apiv3_modules.py | 8 +- .../coprs/views/apiv3_ns/apiv3_packages.py | 20 ++--- .../coprs/views/apiv3_ns/apiv3_permissions.py | 20 ++--- .../views/apiv3_ns/apiv3_project_chroots.py | 12 +-- .../coprs/views/apiv3_ns/apiv3_projects.py | 32 +++---- .../coprs/views/apiv3_ns/apiv3_webhooks.py | 8 +- frontend/coprs_frontend/coprs/views/misc.py | 85 ++++++++----------- 11 files changed, 127 insertions(+), 183 deletions(-) diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/__init__.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/__init__.py index 0b1ac425d..0391c1238 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/__init__.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/__init__.py @@ -95,39 +95,6 @@ def query_params_wrapper(*args, **kwargs): return query_params_decorator -def _shared_pagination_wrapper(**kwargs): - form = PaginationForm(flask.request.args) - if not form.validate(): - raise CoprHttpException(form.errors) - kwargs.update(form.data) - return kwargs - - -def pagination(): - def pagination_decorator(f): - @wraps(f) - def pagination_wrapper(*args, **kwargs): - kwargs = _shared_pagination_wrapper(**kwargs) - return f(*args, **kwargs) - return pagination_wrapper - return pagination_decorator - - -def _shared_file_upload_wrapper(): - data = json.loads(flask.request.files["json"].read()) or {} - flask.request.form = ImmutableMultiDict(list(data.items())) - -def file_upload(): - def file_upload_decorator(f): - @wraps(f) - def file_upload_wrapper(*args, **kwargs): - if "json" in flask.request.files: - _shared_file_upload_wrapper() - return f(*args, **kwargs) - return file_upload_wrapper - return file_upload_decorator - - class PaginationForm(wtforms.Form): limit = wtforms.IntegerField("Limit", validators=[wtforms.validators.Optional()]) offset = wtforms.IntegerField("Offset", validators=[wtforms.validators.Optional()]) @@ -249,27 +216,6 @@ def get(self): return objects[self.offset : limit] -def _check_if_user_can_edit_copr(ownername, projectname): - copr = get_copr(ownername, projectname) - if not flask.g.user.can_edit(copr): - raise AccessRestricted( - "User '{0}' can not see permissions for project '{1}' " \ - "(missing admin rights)".format( - flask.g.user.name, - '/'.join([ownername, projectname]) - ) - ) - return copr - - -def editable_copr(f): - @wraps(f) - def wrapper(ownername, projectname): - copr = _check_if_user_can_edit_copr(ownername, projectname) - return f(copr) - return wrapper - - def set_defaults(formdata, form_class): """ Take a `formdata` which can be `flask.request.form` or an output from @@ -481,42 +427,55 @@ def call_deprecated_endpoint_method(endpoint_method): return call_deprecated_endpoint_method -def restx_editable_copr(endpoint_method): +def editable_copr(endpoint_method): """ Raises an exception if user don't have permissions for editing Copr repo. Order matters! If flask.g.user is None then this will fail! If used with @api_login_required it has to be called after it: @api_login_required - @restx_editable_copr + @editable_copr ... """ @wraps(endpoint_method) def editable_copr_getter(self, ownername, projectname): - copr = _check_if_user_can_edit_copr(ownername, projectname) + copr = get_copr(ownername, projectname) + if not flask.g.user.can_edit(copr): + raise AccessRestricted( + "User '{0}' can not see permissions for project '{1}' " \ + "(missing admin rights)".format( + flask.g.user.name, + '/'.join([ownername, projectname]) + ) + ) + return endpoint_method(self, copr) return editable_copr_getter -def restx_pagination(endpoint_method): +def pagination(endpoint_method): """ Validates pagination arguments and converts pagination parameters from query to kwargs. """ @wraps(endpoint_method) def create_pagination(self, *args, **kwargs): - kwargs = _shared_pagination_wrapper(**kwargs) + form = PaginationForm(flask.request.args) + if not form.validate(): + raise CoprHttpException(form.errors) + kwargs.update(form.data) return endpoint_method(self, *args, **kwargs) return create_pagination -def restx_file_upload(endpoint_method): +def file_upload(endpoint_method): """ Allow uploading a file to a form via endpoint by using this function as an endpoint decorator. """ @wraps(endpoint_method) def inner(self, *args, **kwargs): if "json" in flask.request.files: - _shared_file_upload_wrapper() + data = json.loads(flask.request.files["json"].read()) or {} + flask.request.form = ImmutableMultiDict(list(data.items())) return endpoint_method(self, *args, **kwargs) return inner diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_build_chroots.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_build_chroots.py index df881f519..2301ff461 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_build_chroots.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_build_chroots.py @@ -18,7 +18,7 @@ build_chroot_config_model, nevra_packages_model, ) -from coprs.views.apiv3_ns import restx_pagination +from coprs.views.apiv3_ns import pagination from . import Paginator @@ -83,7 +83,7 @@ def get(self, build_id, chrootname): doc={"deprecated": True, "description": "Use query parameters instead"}, ) class BuildChrootList(Resource): - @restx_pagination + @pagination @query_to_parameters @apiv3_bchroots_ns.doc(params=build_id_params | pagination_params) @apiv3_bchroots_ns.marshal_list_with(pagination_build_chroot_model) diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_builds.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_builds.py index 2ddc3207b..e4d49e3ca 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_builds.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_builds.py @@ -13,7 +13,7 @@ from copr_common.enums import StatusEnum from coprs import db, forms, models from coprs.exceptions import (BadRequest, AccessRestricted) -from coprs.views.misc import restx_api_login_required +from coprs.views.misc import api_login_required from coprs.views.apiv3_ns import api, rename_fields_helper, deprecated_route_method_type from coprs.views.apiv3_ns.schema.schemas import build_model, pagination_build_model, source_chroot_model, \ source_build_config_model, list_build_params, create_build_url_input_model, create_build_upload_input_model, \ @@ -29,8 +29,8 @@ SubqueryPaginator, json2form, query_to_parameters, - restx_pagination, - restx_file_upload, + pagination, + file_upload, ) from .json2form import get_form_compatible_data @@ -141,7 +141,7 @@ def get(self, build_id): @apiv3_builds_ns.route("/list") class ListBuild(Resource): - @restx_pagination + @pagination @query_to_parameters @apiv3_builds_ns.doc(params=list_build_params) @apiv3_builds_ns.marshal_with(pagination_build_model) @@ -237,7 +237,7 @@ def _common(build_id): db.session.commit() return to_dict(build) - @restx_api_login_required + @api_login_required @apiv3_builds_ns.doc(params=get_build_docs) @apiv3_builds_ns.marshal_with(build_model) def put(self, build_id): @@ -247,7 +247,7 @@ def put(self, build_id): """ return self._common(build_id) - @restx_api_login_required + @api_login_required @apiv3_builds_ns.doc(params=get_build_docs) @apiv3_builds_ns.marshal_with(build_model) @deprecated_route_method_type(apiv3_builds_ns, "POST", "PUT") @@ -261,7 +261,7 @@ def post(self, build_id): @apiv3_builds_ns.route("/create/url") class CreateFromUrl(Resource): - @restx_api_login_required + @api_login_required @apiv3_builds_ns.expect(create_build_url_input_model) @apiv3_builds_ns.marshal_with(pagination_build_model) def post(self): @@ -288,8 +288,8 @@ def create_new_build(options): @apiv3_builds_ns.route("/create/upload") class CreateFromUpload(Resource): - @restx_file_upload - @restx_api_login_required + @file_upload + @api_login_required @apiv3_builds_ns.expect(create_build_upload_input_model) @apiv3_builds_ns.marshal_with(build_model) def post(self): @@ -315,7 +315,7 @@ def create_new_build(options): @apiv3_builds_ns.route("/create/scm") class CreateFromScm(Resource): - @restx_api_login_required + @api_login_required @apiv3_builds_ns.expect(create_build_scm_input_model) @apiv3_builds_ns.marshal_with(build_model) def post(self): @@ -346,7 +346,7 @@ def create_new_build(options): @apiv3_builds_ns.route("/create/distgit") class CreateFromDistGit(Resource): - @restx_api_login_required + @api_login_required @apiv3_builds_ns.expect(create_build_distgit_input_model) @apiv3_builds_ns.marshal_with(build_model) def post(self): @@ -375,7 +375,7 @@ def create_new_build(options): @apiv3_builds_ns.route("/create/pypi") class CreateFromPyPi(Resource): - @restx_api_login_required + @api_login_required @apiv3_builds_ns.expect(create_build_pypi_input_model) @apiv3_builds_ns.marshal_with(build_model) def post(self): @@ -409,7 +409,7 @@ def create_new_build(options): @apiv3_builds_ns.route("/create/rubygems") class CreateFromRubyGems(Resource): - @restx_api_login_required + @api_login_required @apiv3_builds_ns.expect(create_build_rubygems_input_model) @apiv3_builds_ns.marshal_with(build_model) def post(self): @@ -435,7 +435,7 @@ def create_new_build(options): @apiv3_builds_ns.route("/create/custom") class CreateCustom(Resource): - @restx_api_login_required + @api_login_required @apiv3_builds_ns.expect(create_build_custom_input_model) @apiv3_builds_ns.marshal_with(build_model) def post(self): @@ -465,7 +465,7 @@ def create_new_build(options): @apiv3_builds_ns.route("/delete/") class DeleteBuild(Resource): - @restx_api_login_required + @api_login_required @apiv3_builds_ns.doc(params=get_build_docs) @apiv3_builds_ns.marshal_with(build_model) def delete(self, build_id): @@ -490,7 +490,7 @@ def _common(): db.session.commit() return {"builds": build_ids} - @restx_api_login_required + @api_login_required @apiv3_builds_ns.expect(delete_builds_input_model) @apiv3_builds_ns.marshal_with(list_build_model) @deprecated_route_method_type(apiv3_builds_ns, "POST", "DELETE") @@ -501,7 +501,7 @@ def post(self): """ return self._common() - @restx_api_login_required + @api_login_required @apiv3_builds_ns.expect(delete_builds_input_model) @apiv3_builds_ns.marshal_with(list_build_model) def delete(self): @@ -516,7 +516,7 @@ def delete(self): # this endoint is not meant to be used by the end user @apiv3_builds_ns.hide class CheckBeforeBuild(Resource): - @restx_api_login_required + @api_login_required @apiv3_builds_ns.doc( responses={200: {"message": "It should be safe to submit a build like this"}} ) diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_general.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_general.py index 38eb9b504..7836ac91b 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_general.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_general.py @@ -12,7 +12,7 @@ from coprs import app, oid, db from coprs.views.apiv3_ns import api from coprs.exceptions import AccessRestricted -from coprs.views.misc import restx_api_login_required +from coprs.views.misc import api_login_required from coprs.auth import UserAuth @@ -64,7 +64,7 @@ def krb_straighten_username(krb_remote_user): @apiv3_general_ns.route("/auth-check") class AuthCheck(Resource): - @restx_api_login_required + @api_login_required def get(self): """ Check if the user is authenticated diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_modules.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_modules.py index 277393b10..3bbf61e95 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_modules.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_modules.py @@ -10,10 +10,10 @@ from wtforms import ValidationError from coprs import forms, db_session_scope -from coprs.views.apiv3_ns import api, get_copr, restx_file_upload +from coprs.views.apiv3_ns import api, get_copr, file_upload from coprs.views.apiv3_ns.schema.schemas import (module_build_model, fullname_params, module_add_input_model) -from coprs.views.misc import restx_api_login_required +from coprs.views.misc import api_login_required from coprs.exceptions import DuplicateException, BadRequest, InvalidForm from coprs.logic.modules_logic import ModuleProvider, ModuleBuildFacade @@ -30,8 +30,8 @@ def to_dict(module): @apiv3_module_ns.route("/build//") class Module(Resource): - @restx_api_login_required - @restx_file_upload + @api_login_required + @file_upload @apiv3_module_ns.doc(params=fullname_params) @apiv3_module_ns.expect(module_add_input_model) @apiv3_module_ns.marshal_with(module_build_model) diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_packages.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_packages.py index de17534b4..c729f7c36 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_packages.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_packages.py @@ -15,13 +15,13 @@ UnknownSourceTypeException, InvalidForm, ) -from coprs.views.misc import restx_api_login_required +from coprs.views.misc import api_login_required from coprs import db, models, forms, helpers from coprs.views.apiv3_ns import ( api, rename_fields_helper, query_to_parameters, - restx_pagination, + pagination, deprecated_route_method_type, ) from coprs.views.apiv3_ns.schema.schemas import ( @@ -140,7 +140,7 @@ def get(self, ownername, projectname, packagename, with_latest_build=False, @apiv3_packages_ns.route("/list") class PackageGetList(Resource): - @restx_pagination + @pagination @query_to_parameters @apiv3_packages_ns.doc(params=package_get_list_params) @apiv3_packages_ns.marshal_with(pagination_package_model) @@ -178,7 +178,7 @@ def get(self, ownername, projectname, with_latest_build=False, @apiv3_packages_ns.route("/add////") class PackageAdd(Resource): - @restx_api_login_required + @api_login_required @apiv3_packages_ns.doc(params=add_package_docs) @apiv3_packages_ns.expect(package_add_input_model) @apiv3_packages_ns.marshal_with(package_model) @@ -200,7 +200,7 @@ def post(self, ownername, projectname, package_name, source_type_text): @apiv3_packages_ns.route("/edit////") @apiv3_packages_ns.route("/edit////") class PackageEdit(Resource): - @restx_api_login_required + @api_login_required @apiv3_packages_ns.doc(params=edit_package_docs) @apiv3_packages_ns.expect(package_edit_input_model) @apiv3_packages_ns.marshal_with(package_model) @@ -245,7 +245,7 @@ def _common(): db.session.commit() return to_dict(package) - @restx_api_login_required + @api_login_required @apiv3_packages_ns.marshal_with(package_model) @apiv3_packages_ns.expect(base_package_input_model) def put(self): @@ -256,7 +256,7 @@ def put(self): return self._common() @deprecated_route_method_type(apiv3_packages_ns, "POST", "PUT") - @restx_api_login_required + @api_login_required @apiv3_packages_ns.marshal_with(package_model) @apiv3_packages_ns.expect(base_package_input_model) def post(self): @@ -269,7 +269,7 @@ def post(self): @apiv3_packages_ns.route("/build") class PackageBuild(Resource): - @restx_api_login_required + @api_login_required @apiv3_packages_ns.marshal_with(build_model) def post(self): """ @@ -321,7 +321,7 @@ def _common(): db.session.commit() return to_dict(package) - @restx_api_login_required + @api_login_required @apiv3_packages_ns.marshal_with(package_model) @apiv3_packages_ns.expect(base_package_input_model) def delete(self): @@ -332,7 +332,7 @@ def delete(self): return self._common() @deprecated_route_method_type(apiv3_packages_ns, "POST", "DELETE") - @restx_api_login_required + @api_login_required @apiv3_packages_ns.marshal_with(package_model) @apiv3_packages_ns.expect(base_package_input_model) def post(self): diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_permissions.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_permissions.py index 0ea4d1568..d21ba1e81 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_permissions.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_permissions.py @@ -6,8 +6,8 @@ from flask_restx import Namespace, Resource -from coprs.views.apiv3_ns import api, restx_editable_copr, get_copr, deprecated_route_method_type -from coprs.views.misc import restx_api_login_required +from coprs.views.apiv3_ns import api, editable_copr, get_copr, deprecated_route_method_type +from coprs.views.misc import api_login_required from coprs.exceptions import ObjectNotFound, BadRequest from coprs.helpers import PermissionEnum from coprs.logic.coprs_logic import CoprPermissionsLogic @@ -44,8 +44,8 @@ def get(self, who, ownername, projectname): @apiv3_permissions_ns.route("/get//") class GetPermissions(Resource): - @restx_api_login_required - @restx_editable_copr + @api_login_required + @editable_copr @apiv3_permissions_ns.doc(params=fullname_params) @apiv3_permissions_ns.response(HTTPStatus.OK.value, HTTPStatus.OK.description) @apiv3_permissions_ns.response( @@ -112,8 +112,8 @@ def _common(copr): return {'updated': list(updated.keys())} - @restx_api_login_required - @restx_editable_copr + @api_login_required + @editable_copr @apiv3_permissions_ns.doc(params=fullname_params) @apiv3_permissions_ns.response(HTTPStatus.OK.value, HTTPStatus.OK.description) @apiv3_permissions_ns.response( @@ -126,8 +126,8 @@ def post(self, copr): """ return self._common(copr) - @restx_api_login_required - @restx_editable_copr + @api_login_required + @editable_copr @apiv3_permissions_ns.doc(params=fullname_params) @apiv3_permissions_ns.response(HTTPStatus.OK.value, HTTPStatus.OK.description) @apiv3_permissions_ns.response( @@ -171,7 +171,7 @@ def _common(ownername, projectname): return {'updated': bool(permission_dict)} @deprecated_route_method_type(apiv3_permissions_ns, "POST", "PUT") - @restx_api_login_required + @api_login_required @apiv3_permissions_ns.doc(params=fullname_params) @apiv3_permissions_ns.response(HTTPStatus.OK.value, HTTPStatus.OK.description) @apiv3_permissions_ns.response( @@ -184,7 +184,7 @@ def post(self, ownername, projectname): """ return self._common(ownername, projectname) - @restx_api_login_required + @api_login_required @apiv3_permissions_ns.doc(params=fullname_params) @apiv3_permissions_ns.response(HTTPStatus.OK.value, HTTPStatus.OK.description) @apiv3_permissions_ns.response( diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_project_chroots.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_project_chroots.py index d6b3b7627..f314ddfcf 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_project_chroots.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_project_chroots.py @@ -4,7 +4,7 @@ import flask from flask_restx import Namespace, Resource -from coprs.views.misc import restx_api_login_required +from coprs.views.misc import api_login_required from coprs.views.apiv3_ns import ( api, rename_fields_helper, @@ -24,7 +24,7 @@ get_copr, str_to_list, reset_to_defaults, - restx_file_upload, + file_upload, ) from .json2form import get_form_compatible_data @@ -150,8 +150,8 @@ def _common(self, ownername, projectname, chrootname): return to_dict(chroot) @deprecated_route_method_type(apiv3_project_chroots_ns, "POST", "PUT") - @restx_file_upload - @restx_api_login_required + @file_upload + @api_login_required @apiv3_project_chroots_ns.doc(params=project_chroot_get_params) @apiv3_project_chroots_ns.marshal_with(project_chroot_model) def post(self, ownername, projectname, chrootname): @@ -161,8 +161,8 @@ def post(self, ownername, projectname, chrootname): """ return self._common(ownername, projectname, chrootname) - @restx_file_upload - @restx_api_login_required + @file_upload + @api_login_required @apiv3_project_chroots_ns.doc(params=project_chroot_get_params) @apiv3_project_chroots_ns.marshal_with(project_chroot_model) def put(self, ownername, projectname, chrootname): diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py index e1949f5e9..681016197 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_projects.py @@ -8,15 +8,15 @@ from coprs.views.apiv3_ns import ( get_copr, - restx_pagination, + pagination, Paginator, set_defaults, deprecated_route_method_type, - restx_editable_copr, + editable_copr, ) from coprs.views.apiv3_ns.json2form import get_form_compatible_data, get_input_dict from coprs import db, models, forms, db_session_scope -from coprs.views.misc import restx_api_login_required +from coprs.views.misc import api_login_required from coprs.views.apiv3_ns import rename_fields_helper, api, query_to_parameters from coprs.views.apiv3_ns.schema.schemas import ( project_model, @@ -137,7 +137,7 @@ def get(self, ownername, projectname): @apiv3_projects_ns.route("/list") class ProjectList(Resource): - @restx_pagination + @pagination @query_to_parameters @apiv3_projects_ns.doc(params=project_params | pagination_params) @apiv3_projects_ns.marshal_list_with(pagination_project_model) @@ -159,7 +159,7 @@ def get(self, ownername=None, **kwargs): @apiv3_projects_ns.route("/search") class ProjectSearch(Resource): - @restx_pagination + @pagination @query_to_parameters @apiv3_projects_ns.doc(params=query_docs) @apiv3_projects_ns.marshal_list_with(pagination_project_model) @@ -183,7 +183,7 @@ def get(self, query, **kwargs): @apiv3_projects_ns.route("/add/") class ProjectAdd(Resource): - @restx_api_login_required + @api_login_required @query_to_parameters @apiv3_projects_ns.doc(params=project_params) @apiv3_projects_ns.marshal_with(project_model) @@ -312,7 +312,7 @@ def _common(ownername, projectname): return to_dict(copr) - @restx_api_login_required + @api_login_required @apiv3_projects_ns.doc(params=fullname_params) @apiv3_projects_ns.marshal_with(project_model) @apiv3_projects_ns.expect(project_edit_input_model) @@ -327,7 +327,7 @@ def put(self, ownername, projectname): """ return self._common(ownername, projectname) - @restx_api_login_required + @api_login_required @apiv3_projects_ns.doc(params=fullname_params) @apiv3_projects_ns.marshal_with(project_model) @apiv3_projects_ns.expect(project_edit_input_model) @@ -394,7 +394,7 @@ def _common(ownername, projectname): return to_dict(fcopr) - @restx_api_login_required + @api_login_required @apiv3_projects_ns.doc(params=fullname_params) @apiv3_projects_ns.marshal_with(project_model) @apiv3_projects_ns.expect(project_fork_input_model) @@ -409,7 +409,7 @@ def post(self, ownername, projectname): """ return self._common(ownername, projectname) - @restx_api_login_required + @api_login_required @apiv3_projects_ns.doc(params=fullname_params) @apiv3_projects_ns.marshal_with(project_model) @apiv3_projects_ns.expect(project_fork_input_model) @@ -446,7 +446,7 @@ def _common(ownername, projectname): raise InvalidForm(form) return copr_dict - @restx_api_login_required + @api_login_required @apiv3_projects_ns.doc(params=fullname_params) @apiv3_projects_ns.marshal_with(project_model) @apiv3_projects_ns.expect(project_delete_input_model) @@ -461,7 +461,7 @@ def delete(self, ownername, projectname): """ return self._common(ownername, projectname) - @restx_api_login_required + @api_login_required @apiv3_projects_ns.doc(params=fullname_params) @apiv3_projects_ns.marshal_with(project_model) @apiv3_projects_ns.expect(project_delete_input_model) @@ -487,8 +487,8 @@ def _common(copr): return to_dict(copr) - @restx_api_login_required - @restx_editable_copr + @api_login_required + @editable_copr @apiv3_projects_ns.doc(params=fullname_params) @apiv3_projects_ns.marshal_with(project_model) @apiv3_projects_ns.response( @@ -500,8 +500,8 @@ def put(self, copr): """ return self._common(copr) - @restx_api_login_required - @restx_editable_copr + @api_login_required + @editable_copr @apiv3_projects_ns.doc(params=fullname_params) @apiv3_projects_ns.marshal_with(project_model) @apiv3_projects_ns.response( diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_webhooks.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_webhooks.py index 7cb82f287..8ebf6d64d 100644 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_webhooks.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_webhooks.py @@ -10,8 +10,8 @@ from flask_restx import Namespace, Resource from coprs import db -from coprs.views.misc import restx_api_login_required -from coprs.views.apiv3_ns import api, restx_editable_copr +from coprs.views.misc import api_login_required +from coprs.views.apiv3_ns import api, editable_copr from coprs.views.apiv3_ns.schema.schemas import fullname_params, webhook_secret_model @@ -35,8 +35,8 @@ def to_dict(copr): @apiv3_webhooks_ns.route("/generate//") class WebhookSecret(Resource): - @restx_api_login_required - @restx_editable_copr + @api_login_required + @editable_copr @apiv3_webhooks_ns.doc(params=fullname_params) @apiv3_webhooks_ns.marshal_with(webhook_secret_model) @apiv3_webhooks_ns.response(HTTPStatus.OK.value, "Webhook secret created") diff --git a/frontend/coprs_frontend/coprs/views/misc.py b/frontend/coprs_frontend/coprs/views/misc.py index 772345979..e413ba2ad 100644 --- a/frontend/coprs_frontend/coprs/views/misc.py +++ b/frontend/coprs_frontend/coprs/views/misc.py @@ -157,53 +157,6 @@ def logout(): return UserAuth.logout() -def _shared_api_login_required_wrapper(): - token = None - api_login = None - if "Authorization" in flask.request.headers: - base64string = flask.request.headers["Authorization"] - base64string = base64string.split()[1].strip() - userstring = base64.b64decode(base64string) - (api_login, token) = userstring.decode("utf-8").split(":") - token_auth = False - if token and api_login: - user = UsersLogic.get_by_api_login(api_login).first() - if (user and user.api_token == token and - user.api_token_expiration >= datetime.date.today()): - token_auth = True - flask.g.user = user - if not token_auth: - url = 'https://' + app.config["PUBLIC_COPR_HOSTNAME"] - url = helpers.fix_protocol_for_frontend(url) - - msg = "Attempting to use invalid or expired API login '%s'" - app.logger.info(msg, api_login) - - output = { - "output": "notok", - "error": "Login invalid/expired. Please visit {0}/api to get or renew your API token.".format(url), - } - jsonout = flask.jsonify(output) - jsonout.status_code = 401 - return jsonout - return None - - -def api_login_required(f): - @functools.wraps(f) - def decorated_function(*args, **kwargs): - # flask.g.user can be already set in case a user is using gssapi auth, - # in that case before_request was called and the user is known. - if flask.g.user is not None: - return f(*args, **kwargs) - retval = _shared_api_login_required_wrapper() - if retval is not None: - return retval - - return f(*args, **kwargs) - return decorated_function - - def login_required(role=RoleEnum("user")): def view_wrapper(f): @functools.wraps(f) @@ -324,7 +277,38 @@ def wrapper(*args, **kwargs): # is done -def restx_api_login_required(endpoint_method): +def _check_api_login(): + token = None + api_login = None + if "Authorization" in flask.request.headers: + base64string = flask.request.headers["Authorization"] + base64string = base64string.split()[1].strip() + userstring = base64.b64decode(base64string) + (api_login, token) = userstring.decode("utf-8").split(":") + token_auth = False + if token and api_login: + user = UsersLogic.get_by_api_login(api_login).first() + if (user and user.api_token == token and + user.api_token_expiration >= datetime.date.today()): + token_auth = True + flask.g.user = user + if not token_auth: + url = 'https://' + app.config["PUBLIC_COPR_HOSTNAME"] + url = helpers.fix_protocol_for_frontend(url) + + msg = "Attempting to use invalid or expired API login '%s'" + app.logger.info(msg, api_login) + + output = { + "output": "notok", + "error": "Login invalid/expired. Please visit {0}/api to get or renew your API token.".format(url), + } + return output, 401 + + return None + + +def api_login_required(endpoint_method): """ Checks whether API login is required for an endpoint which is decorated by this decorator. @@ -338,9 +322,10 @@ def check_if_api_login_is_required(self, *args, **kwargs): # in that case before_request was called and the user is known. if flask.g.user is not None: return endpoint_method(self, *args, **kwargs) - retval = _shared_api_login_required_wrapper() + + retval = _check_api_login() if retval is not None: - return retval.json, retval.status_code + return retval return endpoint_method(self, *args, **kwargs) return check_if_api_login_is_required