From 69c5567adbfffabfc3ed109822ebe5150bbf3366 Mon Sep 17 00:00:00 2001 From: Jiri Kyjovsky Date: Fri, 1 Mar 2024 18:08:41 +0100 Subject: [PATCH] frontend: migrate permissions to flask-restx --- .../coprs/views/apiv3_ns/apiv3_permissions.py | 266 +++++++++++------- 1 file changed, 159 insertions(+), 107 deletions(-) mode change 100644 => 100755 frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_permissions.py diff --git a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_permissions.py b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_permissions.py old mode 100644 new mode 100755 index fc11c51e1..e776eff98 --- a/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_permissions.py +++ b/frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_permissions.py @@ -1,7 +1,14 @@ +# pylint: disable=missing-class-docstring + +from http import HTTPStatus + import flask -from coprs.views.apiv3_ns import apiv3_ns -from coprs.views.misc import api_login_required +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.apiv3_ns.apiv3_projects import apiv3_projects_ns +from coprs.views.misc import restx_api_login_required from coprs.exceptions import ObjectNotFound, BadRequest from coprs.helpers import PermissionEnum from coprs.logic.coprs_logic import CoprPermissionsLogic @@ -9,110 +16,155 @@ from coprs.mail import send_mail, PermissionRequestMessage, PermissionChangeMessage from coprs import db_session_scope, models -from . import GET, PUT, editable_copr, get_copr - - -@apiv3_ns.route("/project/permissions/can_build_in///") -def can_build_in(who, ownername, projectname): - """ - Can a user `who` submit builds in the `ownername/projectname` project? - """ - user = UsersLogic.get(who).one() - copr = get_copr(ownername, projectname) - result = { - "who": user.name, - "ownername": copr.owner.name, - "projectname": copr.name, - "can_build_in": user.can_build_in(copr), - } - return flask.jsonify(result) - - -@apiv3_ns.route("/project/permissions/get//", methods=GET) -@api_login_required -@editable_copr -def get_permissions(copr): - if not copr.copr_permissions: - raise ObjectNotFound( - "No permissions set on {0} project".format(copr.full_name)) - - permissions = {} - for perm in copr.copr_permissions: - permissions[perm.user.name] = { - 'admin': PermissionEnum(perm.copr_admin), - 'builder': PermissionEnum(perm.copr_builder), - } - return flask.jsonify({'permissions': permissions}) - - -@apiv3_ns.route("/project/permissions/set//", methods=PUT) -@api_login_required -@editable_copr -def set_permissions(copr): - permissions = flask.request.get_json() - if not isinstance(permissions, dict): - raise BadRequest( - "request is not a dictionary, expected format: " - "{'username': {'admin': 'nothing', 'builder': 'request'} ...}") - - if not permissions: - raise BadRequest("no permission change requested") - - updated = {} - messages = [] - with db_session_scope(): - for username, perm_set in permissions.items(): - user = models.User.query.filter_by(username=username).first() - if not user: - raise BadRequest("user '{0}' doesn't exist in database".format( - username)) - - permission_dict = {} - for perm, state in perm_set.items(): - change = CoprPermissionsLogic.set_permissions( - flask.g.user, copr, user, perm, state) - if change: - updated[username] = True - permission_dict['old_'+perm] = change[0] - permission_dict['new_'+perm] = change[1] - - if permission_dict: - msg = PermissionChangeMessage(copr, permission_dict) - messages.append({'address': user.mail, 'message': msg}) - - # send emails only if transaction succeeded - for task in messages: - if flask.current_app.config.get("SEND_EMAILS", False): - send_mail([task['address']], task['message']) - - return flask.jsonify({'updated': list(updated.keys())}) - - -@apiv3_ns.route("/project/permissions/request//", methods=PUT) -@api_login_required -def request_permissions(ownername, projectname): - copr = get_copr(ownername, projectname) - roles = flask.request.get_json() - if not isinstance(roles, dict): - raise BadRequest("invalid 'roles' dict format, expected: " - "{'admin': True, 'builder': False}") - if not roles: - raise BadRequest("no permission requested") - - permission_dict = {} - with db_session_scope(): - for permission, request_bool in roles.items(): - change = CoprPermissionsLogic.request_permission( - copr, flask.g.user, permission, request_bool) - if change: - permission_dict['old_'+permission] = change[0] - permission_dict['new_'+permission] = change[1] - - if permission_dict: - msg = PermissionRequestMessage(copr, flask.g.user, permission_dict) - for address in copr.admin_mails: +apiv3_permissions_ns = Namespace("permissions", parent=apiv3_projects_ns, description="Permissions") +api.add_namespace(apiv3_permissions_ns) + + +@apiv3_permissions_ns.route("/can_build_in///") +class CanBuild(Resource): + def get(self, who, ownername, projectname): + """ + Can user submit builds in the project? + Can a user `who` submit builds in the `ownername/projectname` project? + """ + user = UsersLogic.get(who).one() + copr = get_copr(ownername, projectname) + result = { + "who": user.name, + "ownername": copr.owner.name, + "projectname": copr.name, + "can_build_in": user.can_build_in(copr), + } + return result + + +@apiv3_permissions_ns.route("/project/permissions/get//") +class GetPermissions(Resource): + @restx_api_login_required + @restx_editable_copr + def get(self, copr): + """ + Get permissions for the project + Get permission for the `ownername/projectname` project. + """ + if not copr.copr_permissions: + raise ObjectNotFound( + "No permissions set on {0} project".format(copr.full_name)) + + permissions = {} + for perm in copr.copr_permissions: + permissions[perm.user.name] = { + 'admin': PermissionEnum(perm.copr_admin), + 'builder': PermissionEnum(perm.copr_builder), + } + + return {'permissions': permissions} + + +@apiv3_permissions_ns.route("/project/permissions/set//") +class SetPermissions(Resource): + @staticmethod + def _common(copr): + permissions = flask.request.get_json() + if not isinstance(permissions, dict): + raise BadRequest( + "request is not a dictionary, expected format: " + "{'username': {'admin': 'nothing', 'builder': 'request'} ...}") + + if not permissions: + raise BadRequest("no permission change requested") + + updated = {} + messages = [] + with db_session_scope(): + for username, perm_set in permissions.items(): + user = models.User.query.filter_by(username=username).first() + if not user: + raise BadRequest("user '{0}' doesn't exist in database".format( + username)) + + permission_dict = {} + for perm, state in perm_set.items(): + change = CoprPermissionsLogic.set_permissions( + flask.g.user, copr, user, perm, state) + if change: + updated[username] = True + permission_dict['old_' + perm] = change[0] + permission_dict['new_' + perm] = change[1] + + if permission_dict: + msg = PermissionChangeMessage(copr, permission_dict) + messages.append({'address': user.mail, 'message': msg}) + + # send emails only if transaction succeeded + for task in messages: if flask.current_app.config.get("SEND_EMAILS", False): - send_mail([address], msg) - - return flask.jsonify({'updated': bool(permission_dict)}) + send_mail([task['address']], task['message']) + + return {'updated': list(updated.keys())} + + @restx_api_login_required + @restx_editable_copr + def post(self, copr): + """ + Create permissions for the project + Create permission for the `ownername/projectname` project. + """ + return self._common(copr) + + @restx_api_login_required + @restx_editable_copr + def put(self, copr): + """ + Change permissions for the project + Change permission for the `ownername/projectname` project. + """ + return self._common(copr) + + +@apiv3_permissions_ns.route("/project/permissions/request//") +class RequestPermission(Resource): + @staticmethod + def _common(ownername, projectname): + copr = get_copr(ownername, projectname) + roles = flask.request.get_json() + if not isinstance(roles, dict): + raise BadRequest("invalid 'roles' dict format, expected: " + "{'admin': True, 'builder': False}") + if not roles: + raise BadRequest("no permission requested") + + permission_dict = {} + with db_session_scope(): + for permission, request_bool in roles.items(): + change = CoprPermissionsLogic.request_permission( + copr, flask.g.user, permission, request_bool) + if change: + permission_dict['old_' + permission] = change[0] + permission_dict['new_' + permission] = change[1] + + if permission_dict: + msg = PermissionRequestMessage(copr, flask.g.user, permission_dict) + for address in copr.admin_mails: + if flask.current_app.config.get("SEND_EMAILS", False): + send_mail([address], msg) + + return {'updated': bool(permission_dict)} + + @deprecated_route_method_type(apiv3_projects_ns, "POST", "PUT") + @restx_api_login_required + def post(self, ownername, projectname): + """ + Request permissions for the project + Request permissions (admin, builder, ...) for the `ownername/projectname` project. + """ + return self._common(ownername, projectname) + + @restx_api_login_required + def put(self, ownername, projectname): + """ + Request permissions for the project + Request permissions (admin, builder, ...) for the `ownername/projectname` project. + """ + return self._common(ownername, projectname)