Skip to content

Commit

Permalink
frontend: migrate permissions to flask-restx
Browse files Browse the repository at this point in the history
  • Loading branch information
nikromen committed Mar 1, 2024
1 parent a39fd37 commit da19cdc
Showing 1 changed file with 159 additions and 107 deletions.
266 changes: 159 additions & 107 deletions frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_permissions.py
Original file line number Diff line number Diff line change
@@ -1,118 +1,170 @@
# 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
from coprs.logic.users_logic import UsersLogic
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/<who>/<ownername>/<projectname>")
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/<ownername>/<projectname>", 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/<ownername>/<projectname>", 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/<ownername>/<projectname>", 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/<who>/<ownername>/<projectname>")
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/<ownername>/<projectname>")
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/<ownername>/<projectname>")
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/<ownername>/<projectname>")
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)

0 comments on commit da19cdc

Please sign in to comment.