Commit 569f3b2d authored by Barbora Kompišová's avatar Barbora Kompišová
Browse files

permissions refactor, notifications update

parent 435c8697
......@@ -429,7 +429,7 @@ class Role(db.Model, EntityBase):
def set_permissions(self, **kwargs):
"""Sets permissions for the role
Args:
**kwargs(dict): Permissions
**kwargs: Permissions
"""
for k, w in kwargs.items():
if hasattr(self.permissions, k) and k not in ('id', 'role_id', 'role'):
......
......@@ -233,3 +233,4 @@ user_list_update_schema = UserListUpdateSchema(strict=True)
group_import_schema = GroupImportSchema(strict=True)
component_schema = ComponentSchema(strict=True)
components_schema = ComponentSchema(strict=True, many=True)
......@@ -3,7 +3,7 @@ from flask import Blueprint
from flask_jwt_extended import jwt_required
from flask_restful import Api, Resource
from portal.rest import component_schema, rest_helpers
from portal.rest import component_schema, rest_helpers, components_schema
from portal.service import permissions, auth
from portal.service.auth import find_client
from portal.service.components import create_component, delete_component, update_component, \
......@@ -27,7 +27,7 @@ class ComponentList(Resource):
raise ForbiddenError(uid=client.id)
components_list = find_all_components()
return component_schema.dump(components_list), 200
return components_schema.dump(components_list)[0], 200
@error_handler
@jwt_required
......
......@@ -6,7 +6,8 @@ from flask_restful import Api, Resource
from portal.rest import course_schema, courses_schema, course_import_schema, rest_helpers
from portal.service.courses import delete_course, update_course, create_course, \
update_notes_token, copy_course, filter_course_dump, find_all_courses
update_notes_token, copy_course, find_all_courses
from portal.service.filters import filter_course_dump
from portal.service.general import find_course
from portal.service.errors import ForbiddenError
from portal.service.permissions import check_client
......
......@@ -7,12 +7,12 @@ from flask_restful import Api, Resource
from portal.service import general, auth
from portal.service.groups import delete_group, update_group, create_group, \
update_user_group_membership, find_users_in_group_by_role, add_single_user_to_group, \
remove_single_user_from_group, import_group
remove_single_user_from_group, import_group, list_groups
from portal.service.permissions import check_client
from portal.tools.decorators import error_handler
from portal.rest import group_schema, groups_schema, users_schema, user_list_update_schema, \
group_import_schema, rest_helpers
from portal.service.errors import PortalAPIError, ForbiddenError
from portal.service.errors import ForbiddenError
groups = Blueprint('groups', __name__)
groups_api = Api(groups)
......@@ -27,9 +27,8 @@ class GroupResource(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['view_course_full']) \
or not check_client(client=client, course=course,
permissions=['view_course_limited']):
permissions = ['view_course_full', 'view_course_limited', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
group = general.find_group(course, gid)
......@@ -41,7 +40,7 @@ class GroupResource(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_groups']):
if not check_client(client=client, course=course, permissions=['update_course']):
raise ForbiddenError(uid=client.id)
group = general.find_group(course, gid)
......@@ -54,7 +53,8 @@ class GroupResource(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_groups']):
permissions = ['write_groups', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
data = rest_helpers.parse_request_data(
......@@ -73,10 +73,11 @@ class GroupsList(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['read_groups']):
permissions = ['read_groups', 'update_course', 'write_groups']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
return groups_schema.dump(course.groups)
return groups_schema.dump(list_groups(course, client=client))
@error_handler
@jwt_required
......@@ -84,7 +85,7 @@ class GroupsList(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_groups']):
if not check_client(client=client, course=course, permissions=['update_course']):
raise ForbiddenError(uid=client.id)
data = rest_helpers.parse_request_data(
......@@ -102,7 +103,8 @@ class GroupUsersList(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['read_groups']):
permissions = ['read_groups', 'update_course', 'write_groups']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
role_id = request.args.get('role')
......@@ -117,7 +119,8 @@ class GroupUsersList(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_groups']):
permissions = ['write_groups', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
data = rest_helpers.parse_request_data(
......@@ -138,7 +141,8 @@ class GroupUser(Resource):
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_groups']):
permissions = ['write_groups', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
group = general.find_group(course, gid)
......@@ -153,7 +157,7 @@ class GroupUser(Resource):
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_groups']):
if not check_client(client=client, course=course, permissions=['update_course']):
raise ForbiddenError(uid=client.id)
group = general.find_group(course, gid)
......@@ -169,7 +173,8 @@ class GroupImport(Resource):
client = auth.find_client()
target_course = general.find_course(cid)
# authorization
if not check_client(client=client, course=target_course, permissions=['write_groups']):
permissions = ['write_groups', 'update_course']
if not check_client(client=client, course=target_course, permissions=permissions):
raise ForbiddenError(uid=client.id)
data = rest_helpers.parse_request_data(
......
from flask_jwt_extended import jwt_required
from flask_restful import Resource
from portal.service import auth, permissions
from portal.service.errors import ForbiddenError
from portal.tools.decorators import error_handler
class NotificationResource(Resource):
@error_handler
@jwt_required
def post(self, notification_type):
client = auth.find_client()
if not (permissions.check_sysadmin(client) or
permissions.check_component(component=client)):
raise ForbiddenError(uid=client.id)
......@@ -10,10 +10,10 @@ from portal.rest import project_schema, projects_schema, config_schema, submissi
from portal.service import auth, general
from portal.service.permissions import check_client
from portal.service.projects import delete_project, update_project, create_project, \
update_project_config, find_project_submissions, can_create_submission
update_project_config, find_project_submissions, can_create_submission, list_projects
from portal.service.submissions import create_submission
from portal.tools.decorators import error_handler
from portal.service.errors import PortalAPIError, ForbiddenError
from portal.service.errors import ForbiddenError
projects = Blueprint('projects', __name__)
projects_api = Api(projects)
......@@ -28,13 +28,11 @@ class ProjectResource(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not (check_client(client=client, course=course, permissions=['view_course_full'])
or not check_client(client=client, course=course,
permissions=['view_course_limited'])):
permissions = ['view_course_full', 'view_course_limited']
if not (check_client(client=client, course=course, permissions=permissions)):
raise ForbiddenError(uid=client.id)
project = general.find_project(course, pid)
return project_schema.dump(project)
@error_handler
......@@ -42,11 +40,11 @@ class ProjectResource(Resource):
def delete(self, cid, pid):
client = auth.find_client()
course = general.find_course(cid)
project = general.find_project(course, pid)
# authorization
if not check_client(client=client, course=course, permissions=['write_projects']):
if not check_client(client=client, course=course, permissions=['update_course']):
raise ForbiddenError(uid=client.id)
project = general.find_project(course, pid)
delete_project(project)
return '', 204
......@@ -55,15 +53,16 @@ class ProjectResource(Resource):
def put(self, cid, pid):
client = auth.find_client()
course = general.find_course(cid)
project = general.find_project(course, pid)
# authorization
if not check_client(client=client, course=course, permissions=['write_projects']):
permissions = ['write_projects', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
data = rest_helpers.parse_request_data(
project_schema, action='update', resource='project'
)
project = general.find_project(course, pid)
update_project(project, data)
return '', 204
......@@ -74,10 +73,7 @@ class ProjectsList(Resource):
def get(self, cid):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_projects']):
raise ForbiddenError(uid=client.id)
return projects_schema.dump(course.projects)
return projects_schema.dump(list_projects(course, client))
@error_handler
@jwt_required
......@@ -85,7 +81,7 @@ class ProjectsList(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_projects']):
if not check_client(client=client, course=course, permissions=['update_course']):
raise ForbiddenError(uid=client.id)
data = rest_helpers.parse_request_data(
......@@ -103,7 +99,8 @@ class ProjectConfigResource(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['read_projects']):
permissions = ['read_projects', 'write_projects', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
project = general.find_project(course, pid)
......@@ -115,7 +112,8 @@ class ProjectConfigResource(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_projects']):
permissions = ['write_projects', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
data = rest_helpers.parse_request_data(
......
import logging
from flask import Blueprint, request
from flask import Blueprint
from flask_jwt_extended import jwt_required
from flask_restful import Api, Resource
from portal.rest import role_schema, roles_schema, users_schema, user_list_update_schema, \
permissions_schema, rest_helpers
from portal.service import auth, general
from portal.service.errors import PortalAPIError, ForbiddenError
from portal.service.errors import ForbiddenError
from portal.service.permissions import check_client
from portal.service.roles import delete_role, update_role, create_role, update_role_permissions, \
update_users_membership_in_role, add_single_user_to_role, remove_single_user_from_role
update_users_membership_in_role, add_single_user_to_role, remove_single_user_from_role, \
list_roles
from portal.tools.decorators import error_handler
roles = Blueprint('roles', __name__)
......@@ -26,9 +27,8 @@ class RoleResource(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not (check_client(client=client, course=course, permissions=['view_course_full'])
or not check_client(client=client, course=course,
permissions=['view_course_limited'])):
permissions = ['view_course_full', 'view_course_limited', 'update_course']
if not (check_client(client=client, course=course, permissions=permissions)):
raise ForbiddenError(uid=client.id)
role = general.find_role(course, rid)
......@@ -40,7 +40,7 @@ class RoleResource(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_roles']):
if not check_client(client=client, course=course, permissions=['update_course']):
raise ForbiddenError(uid=client.id)
role = general.find_role(course, rid)
......@@ -62,7 +62,7 @@ class RoleResource(Resource):
role = general.find_role(course, rid)
update_role(role, data)
return role_schema.dump(role), 204
return '', 204
class RoleList(Resource):
......@@ -71,11 +71,7 @@ class RoleList(Resource):
def get(self, cid):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['read_roles']):
raise ForbiddenError(uid=client.id)
return roles_schema.dump(course.roles)
return roles_schema.dump(list_roles(course, client))
@error_handler
@jwt_required
......@@ -83,7 +79,7 @@ class RoleList(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_roles']):
if not check_client(client=client, course=course, permissions=['update_course']):
raise ForbiddenError(uid=client.id)
data = rest_helpers.parse_request_data(
......@@ -100,7 +96,8 @@ class RolePermissions(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['read_roles']):
permissions = ['read_roles', 'write_roles', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
role = general.find_role(course, rid)
......@@ -112,7 +109,8 @@ class RolePermissions(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_roles']):
permissions = ['write_roles', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
data = rest_helpers.parse_request_data(
......@@ -131,7 +129,8 @@ class RoleUsersList(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['read_roles']):
permissions = ['read_roles', 'write_roles', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
role = general.find_role(course, rid)
......@@ -143,7 +142,8 @@ class RoleUsersList(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_roles']):
permissions = ['write_roles', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
data = rest_helpers.parse_request_data(
......@@ -164,7 +164,8 @@ class RoleUser(Resource):
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_roles']):
permissions = ['write_roles', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
role = general.find_role(course, rid)
......@@ -178,7 +179,8 @@ class RoleUser(Resource):
client = auth.find_client()
course = general.find_course(cid)
# authorization
if not check_client(client=client, course=course, permissions=['write_roles']):
permissions = ['write_roles', 'update_course']
if not check_client(client=client, course=course, permissions=permissions):
raise ForbiddenError(uid=client.id)
role = general.find_role(course, rid)
......
import logging
from flask import Blueprint, request
from flask import Blueprint
from flask_jwt_extended import jwt_required
from flask_restful import Api, Resource
......@@ -29,8 +29,7 @@ class SubmissionResource(Resource):
submission = portal.service.general.find_submission(sid)
course = submission.project.course
# authorization
if permissions.check_component(component=client, course=course,
permissions=['read_submissions']):
if permissions.check_component(component=client):
pass
elif permissions.check_user(user=client, course=course,
permissions=['read_submissions_all']):
......@@ -68,8 +67,7 @@ class SubmissionState(Resource):
submission = general.find_submission(sid)
course = submission.project.course
# authorization
if permissions.check_component(component=client, permissions=['read_submission_state'],
course=course):
if permissions.check_component(component=client):
pass
elif permissions.check_user(user=client, course=course,
permissions=['read_submissions_all']):
......@@ -186,8 +184,7 @@ class SubmissionReview(Resource):
submission = general.find_submission(sid)
course = submission.project.course
# authorization
if permissions.check_component(component=client, permissions=['read_reviews_all'],
course=course):
if permissions.check_component(component=client):
pass
elif permissions.check_user(user=client, course=course, permissions=['read_reviews_all']):
pass
......@@ -210,8 +207,7 @@ class SubmissionReview(Resource):
submission = general.find_submission(sid)
# authorization
course = submission.project.course
if permissions.check_component(component=client, permissions=['write_submission_review'],
course=course):
if permissions.check_component(component=client):
pass
elif permissions.check_user(user=client, course=course,
permissions=['write_reviews_all']):
......
......@@ -33,7 +33,7 @@ class UserResource(Resource):
client = find_client()
user = find_user(uid)
# authorization
if permissions.check_component(component=client, permissions=[]) \
if permissions.check_component(component=client) \
or permissions.check_sysadmin(client) \
or client == user:
return user_schema.dump(user)[0], 200
......@@ -45,7 +45,7 @@ class UserResource(Resource):
client = find_client()
user = find_user(uid)
# authorization
if not (permissions.check_component(component=client, permissions=[])
if not (permissions.check_component(component=client)
or permissions.check_sysadmin(client)
or client == user):
raise ForbiddenError(uid=client.id)
......@@ -79,7 +79,7 @@ class UserPassword(Resource):
client = portal.service.auth.find_client()
user = portal.service.general.find_user(uid)
# authorization
if not (permissions.check_component(component=client, permissions=[])
if not (permissions.check_component(component=client)
or permissions.check_sysadmin(client)
or client == user):
raise ForbiddenError(uid=client.id)
......@@ -131,7 +131,7 @@ class UserSubmissionList(Resource):
client = portal.service.auth.find_client()
user = portal.service.general.find_user(uid)
# authorization
if not (permissions.check_component(component=client, permissions=[])
if not (permissions.check_component(component=client)
or permissions.check_sysadmin(client)
or client == user):
raise ForbiddenError(uid=client.id)
......@@ -156,7 +156,7 @@ class UserRoleList(Resource):
client = portal.service.auth.find_client()
user = portal.service.general.find_user(uid)
# authorization TODO: insufficient?
if not (permissions.check_component(component=client, permissions=[])
if not (permissions.check_component(component=client)
or permissions.check_sysadmin(client)
or client == user):
raise ForbiddenError(uid=client.id)
......@@ -174,7 +174,7 @@ class UserCourseList(Resource):
client = portal.service.auth.find_client()
user = portal.service.general.find_user(uid)
# authorization
if not (permissions.check_component(component=client, permissions=[])
if not (permissions.check_component(component=client)
or permissions.check_sysadmin(client)
or client == user):
raise ForbiddenError(uid=client.id)
......@@ -204,7 +204,7 @@ class UserReviewList(Resource):
client = portal.service.auth.find_client()
user = portal.service.general.find_user(uid)
# authorization
if not (permissions.check_component(component=client, permissions=[])
if not (permissions.check_component(component=client)
or permissions.check_sysadmin(client)
or client == user):
raise ForbiddenError(uid=client.id)
......@@ -220,14 +220,14 @@ class UserEffectivePermissions(Resource):
client = portal.service.auth.find_client()
user = portal.service.general.find_user(uid)
# authorization TODO - check
if not (permissions.check_component(component=client, permissions=[])
if not (permissions.check_component(component=client)
or permissions.check_sysadmin(user)
or client == user):
raise ForbiddenError(uid=client.id)
course_id = request.args.get('course')
perm = permissions.get_effective_permissions(user, course_id)
return json.dumps(perm, cls=DateTimeEncoder), 200
return perm, 200
users_api.add_resource(UserResource, '/<string:uid>')
......
......@@ -29,4 +29,4 @@ def delete_component(component: Component):
def find_all_components():
return Component.query.all()
\ No newline at end of file
return Component.query.all()
import logging
from portal.database.models import Course, User, ProjectState
from portal.database.models import Course
from portal.service import general
from portal.service.groups import copy_group
from portal.service.projects import copy_project
from portal.service.roles import copy_role
from portal.tools import time
log = logging.getLogger(__name__)
......@@ -94,65 +93,5 @@ def update_notes_token(course: Course, token: str) -> Course:
return course
def filter_projects_from_course(projects: list, course: Course,
state: ProjectState = ProjectState.ACTIVE) -> list:
"""Filters projects for the course based on their state.
Args:
state(ProjectState): State the project must be in to be included in the result. Defaults to ACTIVE.
projects(list): Project list
course(Course): Course instance
Returns(list): Filtered list of projects
"""
def is_active(p):
return p.state(time.NOW()) == state
active_projects_id = [p.id for p in course.projects if is_active(p)]
projects = [p for p in projects if p['id'] in active_projects_id]
return projects
def filter_roles_from_course(roles: list, course: Course, user: User) -> list:
"""Gets roles in a course the user has
Args:
roles(list): List of roles to filter
course(Course): Course instance
user(User): User instance
Returns(list): Filtered list of roles
"""
user_roles = user.get_roles_in_course(course=course)
user_roles_id = [r.id for r in user_roles]
return [r for r in roles if r['id'] in user_roles_id]
def filter_groups_from_course(groups: list, course: Course, user: User) -> list:
"""Filters groups of a course. Returns only groups the user is part of.
Args:
groups(list): List of groups to filter
course(Course): Course instance
user(User): User instance
Returns(list): Filtered list of groups
</