forked from fedora-copr/copr
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
frontend: migrate permissions to flask-restx
- Loading branch information
Showing
1 changed file
with
159 additions
and
107 deletions.
There are no files selected for viewing
266 changes: 159 additions & 107 deletions
266
frontend/coprs_frontend/coprs/views/apiv3_ns/apiv3_permissions.py
100644 → 100755
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |