diff --git a/flask-backend/api/__init__.py b/flask-backend/api/__init__.py index 9ac0507c..8b1f4600 100644 --- a/flask-backend/api/__init__.py +++ b/flask-backend/api/__init__.py @@ -44,4 +44,7 @@ def unauthorized_handler(): from .routes.extraction import extraction as extraction_blueprint app.register_blueprint(extraction_blueprint) + from .routes.rolerequests import rolerequests as rolerequests_blueprint + app.register_blueprint(rolerequests_blueprint) + return app \ No newline at end of file diff --git a/flask-backend/api/models/RoleRequest.py b/flask-backend/api/models/RoleRequest.py new file mode 100644 index 00000000..d724922e --- /dev/null +++ b/flask-backend/api/models/RoleRequest.py @@ -0,0 +1,32 @@ +import time +from flask_login import UserMixin + +from .. import db, ma + +class RoleRequest(UserMixin, db.Model): + id = db.Column(db.Integer, primary_key=True) + user_id = db.Column(db.Integer) + admin_id = db.Column(db.Integer) + requested_role = db.Column(db.String(100)) + timestamp = db.Column(db.Float) + + def __init__(self, user_id, admin_id, requested_role): + self.user_id = user_id + self.admin_id = admin_id + self.requested_role = requested_role + self.timestamp = int(time.time()) + + # Return object is JSON format + def map(self): + return { + 'id': self.id, + 'user_id': self.user_id, + 'admin_id': self.admin_id, + 'requested_role': self.requested_role, + 'timestamp': self.timestamp, + } + + +class RoleRequestSchema(ma.Schema): + class Meta: + fields = ('id', 'user_id', 'admin_id', 'requested_role', 'timestamp') \ No newline at end of file diff --git a/flask-backend/api/models/models.py b/flask-backend/api/models/models.py index 172fa3b8..7fcfc05e 100644 --- a/flask-backend/api/models/models.py +++ b/flask-backend/api/models/models.py @@ -50,7 +50,7 @@ def __init__(self, case_name, data_size, timestamp, extractor_id, data_path): class UserSchema(ma.Schema): class Meta: - fields = ('name', 'email', 'role', 'timestamp', 'admin') + fields = ('id', 'name', 'email', 'role', 'timestamp', 'admin') class CaseSchema(ma.Schema): class Meta: diff --git a/flask-backend/api/routes/rolerequests.py b/flask-backend/api/routes/rolerequests.py new file mode 100644 index 00000000..6b05ea73 --- /dev/null +++ b/flask-backend/api/routes/rolerequests.py @@ -0,0 +1,246 @@ +from flask import Blueprint, jsonify, request +from flask_login import login_required, current_user + +from .. import db +from ..models.models import User +from ..models.RoleRequest import RoleRequest, RoleRequestSchema + +rolerequests = Blueprint('rolerequests', __name__, url_prefix='/rolerequests') + +rolerequests_schema = RoleRequestSchema(many=True) + +# Fetch all requests for an admin +@rolerequests.route('/', methods=['GET']) +@login_required +def get_all_rolerequests(): + + # Only admins can view role requests + if current_user.has_admin: + response = { + 'success': False, + 'msg': 'Role requests can only be viewed by an admin', + } + return jsonify(response), 400 + + # Admin can only see the requests of his created users + admin_id = current_user.id + rolerequests = RoleRequest.query.filter_by(admin_id=admin_id).order_by(RoleRequest.timestamp).all() + result = rolerequests_schema.dump(rolerequests) + response = { + 'success': True, + 'data': result, + 'msg': 'Role requests fetched successfully' + } + return jsonify(response), 200 + +# Fetch a request by id +@rolerequests.route('/', methods=['GET']) +@login_required +def get_rolerequest_by_id(id): + + if not id: + response = { + 'success': False, + 'msg': 'Please provide an id', + } + return jsonify(response), 400 + + rolerequest = RoleRequest.query.filter_by(id=id).first() + if not rolerequest: + response = { + 'success': False, + 'msg': 'Role request not found', + } + return jsonify(response), 404 + + # Only the concerned admin or the user who posted this request should be able to access it + if rolerequest.admin_id != current_user.id and rolerequest.user_id != current_user.id: + response = { + 'success': False, + 'msg': 'Not authorized to view this request', + } + return jsonify(response), 401 + + response = { + 'success': True, + 'data': rolerequest, + 'msg': 'Role requests fetched successfully', + } + return jsonify(response), 200 + +# submit a role request +@rolerequests.route('/', methods=['POST']) +@login_required +def submit_role_request(): + + # Only extractor or management can submit a role request + if not current_user.has_admin: + response = { + 'success': False, + 'msg': 'You\'re already an admin', + } + return jsonify(response), 400 + + # Check if requested role is provided or not + try: + req = request.get_json() + requested_role = str(req['requested_role']) + except: + response = { + 'success': False, + 'msg': 'Please provide a role', + } + return jsonify(response), 400 + + # Check if user already has the role he is requesting + if requested_role == current_user.role: + response = { + 'success': False, + 'msg': f'You are already {requested_role}', + } + return jsonify(response), 400 + + # Check if role provided is a valid one + if requested_role not in ['admin', 'extractor', 'management']: + response = { + 'success': False, + 'msg': 'Please provide a valid role', + } + return jsonify(response), 400 + + user_id = current_user.id + + # Find admin using email + admin = User.query.filter_by(email=current_user.admin).first() + + # If admin is absent + if not admin: + response = { + 'success': False, + 'msg': 'Error submiting the request', + } + return jsonify(response), 500 + + admin_id = admin.id + rolerequest = RoleRequest(user_id=user_id, admin_id=admin_id, requested_role=requested_role) + db.session.add(rolerequest) + db.session.commit() + + response = { + 'success': True, + 'data': rolerequest.map(), + 'msg': 'Requested successfully submitted', + } + return jsonify(response), 200 + +# Accept a role request by its id +@rolerequests.route('/accept/', methods=['PUT']) +@login_required +def accept_rolerequest(id): + + # Only admins can accept role requests + if current_user.has_admin: + response = { + 'success': False, + 'msg': 'Role requests can only be accepted by an admin', + } + return jsonify(response), 400 + + if not id: + response = { + 'success': False, + 'msg': 'Please provide an id', + } + return jsonify(response), 400 + + rolerequest = RoleRequest.query.filter_by(id=id).first() + + # Check if request exists + if not rolerequest: + response = { + 'success': False, + 'msg': 'Role request not found', + } + return jsonify(response), 404 + + # Check if request belongs to this admin + if rolerequest.admin_id != current_user.id: + response = { + 'success': False, + 'msg': 'Not authorized to accept this request', + } + return jsonify(response), 401 + + requested_role = rolerequest.requested_role + user = User.query.filter_by(id=rolerequest.user_id).first() + + # Check if user exists + if not user: + response = { + 'success': False, + 'msg': 'User not found', + } + return jsonify(response), 404 + + # Update user role + user.role = requested_role + db.session.commit() + + # Delete the request as it is now resolved + db.session.delete(rolerequest) + db.session.commit() + + response = { + 'success': True, + 'msg': 'Role request accepted', + } + return jsonify(response), 200 + +# Reject a role request by its id +@rolerequests.route('/reject/', methods=['DELETE']) +@login_required +def reject_rolerequest(id): + + # Only admins can reject role requests + if current_user.has_admin: + response = { + 'success': False, + 'msg': 'Role requests can only be rejected by an admin', + } + return jsonify(response), 400 + + if not id: + response = { + 'success': False, + 'msg': 'Please provide an id', + } + return jsonify(response), 400 + + rolerequest = RoleRequest.query.filter_by(id=id).first() + + # Check if request exists + if not rolerequest: + response = { + 'success': False, + 'msg': 'Role request not found', + } + return jsonify(response), 404 + + # Check if request belongs to this admin + if rolerequest.admin_id != current_user.id: + response = { + 'success': False, + 'msg': 'Not authorized to accept this request', + } + return jsonify(response), 401 + + # Delete the request + db.session.delete(rolerequest) + db.session.commit() + + response = { + 'success': True, + 'msg': 'Role request rejected', + } + return jsonify(response), 200 + diff --git a/flask-backend/create_database.py b/flask-backend/create_database.py index 226ee0a9..f839f194 100644 --- a/flask-backend/create_database.py +++ b/flask-backend/create_database.py @@ -1,4 +1,5 @@ from api.models.models import User +from api.models.RoleRequest import RoleRequest from api import db, create_app db.create_all(app=create_app()) \ No newline at end of file