Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revoke a user's admin role #54

Merged
merged 1 commit into from
Jun 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions app/api/dao/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,45 @@
class AdminDAO:

@staticmethod
def assign_new_user(data):
def assign_new_user(assigner_user_id, data):

new_admin_user_id = data['user_id']

if assigner_user_id is new_admin_user_id:
return {"message": "You cannot assign yourself as an Admin."}, 403

new_admin_user = UserModel.find_by_id(new_admin_user_id)

if new_admin_user:

if new_admin_user.is_admin:
return {"message": "User is already an Admin"}, 201
return {"message": "User is already an Admin."}, 400

new_admin_user.is_admin = True
new_admin_user.save_to_db()

return {"message": "User is now an Admin"}, 201
return {"message": "User is now an Admin."}, 200

return {"message": "User does not exist."}, 404

@staticmethod
def revoke_admin_user(revoker_user_id, data):

admin_user_id = data['user_id']

if revoker_user_id is admin_user_id:
return {"message": "You cannot revoke your admin status."}, 403

new_admin_user = UserModel.find_by_id(admin_user_id)

if new_admin_user:

if not new_admin_user.is_admin:
return {"message": "User is not an Admin."}, 400

new_admin_user.is_admin = False
new_admin_user.save_to_db()

return {"message": "User admin status was revoked."}, 200

return {"message": "User does not exist"}, 401
return {"message": "User does not exist."}, 404
4 changes: 2 additions & 2 deletions app/api/dao/mentorship_relation.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def create_mentorship_relation(self, user_id, data):
# validate if mentor user exists
mentor_user = UserModel.find_by_id(mentor_id)
if mentor_user is None:
return {'message': 'Mentor user does not exist.'}, 400
return {'message': 'Mentor user does not exist.'}, 404

# validate if mentor is available to mentor
if not mentor_user.available_to_mentor:
Expand All @@ -53,7 +53,7 @@ def create_mentorship_relation(self, user_id, data):
# validate if mentee user exists
mentee_user = UserModel.find_by_id(mentee_id)
if mentee_user is None:
return {'message': 'Mentee user does not exist.'}, 400
return {'message': 'Mentee user does not exist.'}, 404

# validate if mentee is wants to be mentored
if not mentee_user.need_mentoring:
Expand Down
17 changes: 13 additions & 4 deletions app/api/dao/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class UserDAO:
FAIL_USER_ALREADY_EXISTS = "FAIL_USER_ALREADY_EXISTS"
SUCCESS_USER_CREATED = "SUCCESS_USER_CREATED"
MIN_NUMBER_OF_ADMINS = 1

@staticmethod
def create_user(data):
Expand All @@ -29,12 +30,20 @@ def create_user(data):

@staticmethod
def delete_user(user_id):
user = UserModel.find_by_id(user_id).one()
user = UserModel.find_by_id(user_id)

# check if this user is the only admin
if user.is_admin:

admins_list_count = len(UserModel.get_all_admins())
if admins_list_count <= UserDAO.MIN_NUMBER_OF_ADMINS:
return {"message": "You cannot delete your account, since you are the only Admin left."}, 400

if user:
user.delete_from_db()
return {"message": "User was deleted successfully"}, 201

return {"message": "User does not exist"}, 201
return {"message": "User does not exist"}, 404

@staticmethod
def get_user(user_id):
Expand All @@ -59,7 +68,7 @@ def update_user_profile(user_id, data):
user = UserModel.find_by_id(user_id)

if not user:
return {"message": "User does not exist"}, 201
return {"message": "User does not exist"}, 404

if 'name' in data and data['name']:
user.name = data['name']
Expand Down Expand Up @@ -117,7 +126,7 @@ def change_password(user_id, data):
user.save_to_db()
return {"message": "Password was updated successfully."}, 201

return {"message": "Current password is incorrect."}, 201
return {"message": "Current password is incorrect."}, 400

@staticmethod
def confirm_registration(user_id, data):
Expand Down
4 changes: 2 additions & 2 deletions app/api/models/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@


def add_models_to_namespace(api_namespace):
api_namespace.models[assign_new_admin_request_body.name] = assign_new_admin_request_body
api_namespace.models[assign_and_revoke_user_admin_request_body.name] = assign_and_revoke_user_admin_request_body


assign_new_admin_request_body = Model('Assign User model', {
assign_and_revoke_user_admin_request_body = Model('Assign User model', {
'user_id': fields.Integer(
required=True,
description='The unique identifier of a user'
Expand Down
30 changes: 26 additions & 4 deletions app/api/resources/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from flask import request
from flask_restplus import Resource
from flask_jwt import jwt_required, current_identity

from run import api
from app.api.models.admin import *
from app.api.dao.admin import AdminDAO
Expand All @@ -17,17 +18,38 @@ class AssignNewUserAdmin(Resource):

@classmethod
@jwt_required()
@admin_ns.expect(auth_header_parser, assign_new_admin_request_body, validate=True)
@admin_ns.expect(auth_header_parser, assign_and_revoke_user_admin_request_body, validate=True)
def post(cls):
"""
Assigns a User as a new Admin.
"""

if current_identity.is_admin:
data = request.json
return DAO.assign_new_user(data)
return DAO.assign_new_user(current_identity.id, data)

else:
return {
"message": "You don't have admin status. You can't assign other user as admin."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

403 Forbidden

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed @m-murad (it does not show here because you commented on the line above)

}, 403


@admin_ns.route('admin/remove')
class RevokeUserAdmin(Resource):

@classmethod
@jwt_required()
@admin_ns.expect(auth_header_parser, assign_and_revoke_user_admin_request_body, validate=True)
def post(cls):
"""
Revoke admin status from another User Admin.
"""

if current_identity.is_admin:
data = request.json
return DAO.revoke_admin_user(current_identity.id, data)

else:
return {
"message": "You don't have admin status. You can't assign another admin"
}, 401
"message": "You don't have admin status. You can't revoke other admin user."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

403 Forbidden

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also fixed @m-murad

}, 403
4 changes: 4 additions & 0 deletions app/database/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ def find_by_email(cls, email):
def find_by_id(cls, _id):
return cls.query.filter_by(id=_id).first()

@classmethod
def get_all_admins(cls, is_admin=True):
return cls.query.filter_by(is_admin=is_admin).all()

@classmethod
def is_empty(cls):
return cls.query.first() is None
Expand Down
25 changes: 25 additions & 0 deletions docs/Mentorship Backend.postman_collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,31 @@
},
"response": []
},
{
"name": "POST /admin/remove",
"request": {
"url": "http://127.0.0.1:5000/admin/new",
"method": "POST",
"header": [
{
"key": "Authorization",
"value": "JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1Mjc4NTI3NzEsImlhdCI6MTUyNzg1MjQ3MSwibmJmIjoxNTI3ODUyNDcxLCJpZGVudGl0eSI6MX0.bXm5OrEvZnS6PxI4XQkOF4z-ZcFbYZreanutmYTUWyA",
"description": ""
},
{
"key": "Content-Type",
"value": "application/json",
"description": ""
}
],
"body": {
"mode": "raw",
"raw": "{\n\t\"user_id\": 2\n}"
},
"description": "Assign a new user as an Admin"
},
"response": []
},
{
"name": "GET /mentorship-relations",
"request": {
Expand Down
71 changes: 51 additions & 20 deletions docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,37 @@
]
}
},
"/admin/remove": {
"post": {
"responses": {
"200": {
"description": "Success"
}
},
"summary": "Revoke admin status from another User Admin",
"operationId": "post_revoke_user_admin",
"parameters": [
{
"name": "Authorization",
"in": "header",
"type": "string",
"required": true,
"description": "Authentication access token. E.g.: JWT <access_token>"
},
{
"name": "payload",
"required": true,
"in": "body",
"schema": {
"$ref": "#/definitions/Assign User model"
}
}
],
"tags": [
"Admins"
]
}
},
"/login": {
"post": {
"responses": {
Expand Down Expand Up @@ -153,34 +184,24 @@
}
},
"/user": {
"get": {
"delete": {
"responses": {
"404": {
"description": "User not found."
},
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/User list model"
}
"204": {
"description": "User successfully deleted."
}
},
"summary": "Returns a user",
"operationId": "get_user",
"summary": "Deletes user",
"operationId": "delete_user",
"parameters": [
{
"name": "Authorization",
"in": "header",
"type": "string",
"required": true,
"description": "Authentication access token. E.g.: JWT <access_token>"
},
{
"name": "X-Fields",
"in": "header",
"type": "string",
"format": "mask",
"description": "An optional fields mask"
}
],
"tags": [
Expand Down Expand Up @@ -219,24 +240,34 @@
"Users"
]
},
"delete": {
"get": {
"responses": {
"404": {
"description": "User not found."
},
"204": {
"description": "User successfully deleted."
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/User list model"
}
}
},
"summary": "Deletes user",
"operationId": "delete_user",
"summary": "Returns a user",
"operationId": "get_user",
"parameters": [
{
"name": "Authorization",
"in": "header",
"type": "string",
"required": true,
"description": "Authentication access token. E.g.: JWT <access_token>"
},
{
"name": "X-Fields",
"in": "header",
"type": "string",
"format": "mask",
"description": "An optional fields mask"
}
],
"tags": [
Expand Down
Loading