Loading portal/rest/__init__.py +1 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,7 @@ class RoleSchema(Schema): users = fields.Nested(UserSchema, only=('id', 'uco', 'email', 'username'), many=True) course = fields.Nested(CourseSchema, only=('id', 'name', 'codename')) # this could be done prettier (e.g. flattening the structure, showing only set fields) permissions = fields.Nested('portal.rest.RolePermissionsSchema', exclude=('id', 'role')) permissions = fields.Nested('portal.rest.RolePermissionsSchema') class RolePermissionsSchema(Schema): Loading portal/rest/roles/roles.py +14 −11 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ from flask import Blueprint, request from flask_restful import Api, Resource from portal.database.models import Role from portal.rest import role_schema, roles_schema, users_schema from portal.rest import role_schema, roles_schema, users_schema, user_list_update_schema, permissions_schema from portal.service import service from portal.service.errors import PortalAPIError from portal.tools.decorators import error_handler Loading Loading @@ -50,7 +50,6 @@ class RoleResource(Resource): class RoleList(Resource): @error_handler def get(self, cid): log.info(f"GET to {request.url}") Loading Loading @@ -80,7 +79,7 @@ class RolePermissions(Resource): log.info(f"GET to {request.url}") course = service.find_course(cid) role = service.find_role(course, rid) return roles_schema.dump(role.permissions) return permissions_schema.dump(role.permissions) @error_handler def put(self, cid, rid): Loading @@ -92,7 +91,7 @@ class RolePermissions(Resource): if not json_data: raise PortalAPIError(400, message='No data provided for update of role permissions.') data = role_schema.load(json_data)[0] data = permissions_schema.load(json_data)[0] role.set_permissions(**data) log.debug(f"Updated permissions for role {rid} in course {cid} to {data}.") Loading @@ -115,18 +114,22 @@ class RoleUsersList(Resource): role = service.find_role(course, rid) json_data = request.get_json() data = users_schema.load(json_data)[0] data = user_list_update_schema.load(json_data)[0] # TODO: use ids, move to service? # everything from users_add is added, THEN everything from users_remove is subtracted users_old = set(role.users) users_add = data.get('add') users_remove = data.get('remove') if users_add is not None: users_old.union(users_add) if users_remove is not None: users_old.difference(users_remove) users = set() if users_add: to_add = service.find_users(data['add']) users = users_old.union(to_add) if users_remove: to_remove = service.find_users(data['remove']) users = users_old.difference(to_remove) role.users = list(users) service.write_entity(role) log.info(f"Updated users of role {rid} to {data}.") return '', 204 Loading tests/rest/test_project.py +1 −6 Original line number Diff line number Diff line Loading @@ -2,16 +2,11 @@ from datetime import timedelta from flask_jwt_extended import create_access_token from portal.database.models import Group, Course, User, Role, Project from portal.database.models import Course, User, Project from tools.time import NOW, strip_seconds, portal_timezone from . import utils import json ''' * `[POST] /courses/<cid>/projects/<pid>/submissions` : Create submission ''' def test_list(client): cpp = Course.query.filter_by(codename="PB161").first() Loading tests/rest/test_role.py 0 → 100644 +286 −0 Original line number Diff line number Diff line from portal.database.models import Course, Role, User from . import utils import json def test_list(client): cpp = Course.query.filter_by(codename="PB161").first() cpp_roles = len(cpp.roles) response = client.get(f'/courses/{cpp.codename}/roles/') assert response.status_code == 200 assert response.mimetype == 'application/json' roles = json.loads(str(response.get_data().decode("utf-8"))) assert len(roles) == cpp_roles cpp_updated = Course.query.filter_by(codename="PB161").first() for r in roles: utils.assert_role_in(cpp_updated.roles, r) def test_create(client): cpp = Course.query.filter_by(codename="PB161").first() cpp_roles = len(cpp.roles) request_dict = { "name": "assistant", "description": "teacher assistant" } request_json = json.dumps(request_dict) response = client.post(f"/courses/{cpp.codename}/roles/", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 201 assert response.mimetype == 'application/json' new_role = json.loads(str(response.get_data().decode("utf-8"))) cpp_updated = Course.query.filter_by(codename="PB161").first() assert len(cpp_updated.roles) == cpp_roles + 1 assert new_role['name'] == "assistant" assert new_role['description'] == "teacher assistant" assert new_role['id'] utils.assert_role_in(cpp_updated.roles, new_role) def test_read(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] response = client.get(f"/courses/{cpp.codename}/roles/{r.name}") assert response.status_code == 200 assert response.mimetype == 'application/json' role = json.loads(str(response.get_data().decode("utf-8"))) utils.assert_role(r, role) def test_update(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_name = r.name request_dict = dict( name="new role name", description="new role desc", ) request_json = json.dumps(request_dict) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.name == "new role name").first() assert r_updated assert r_updated.description == "new role desc" assert not Role.query.filter(Role.course_id == cpp.id).filter(Role.name == r_name).first() def test_delete(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_name = r.name cpp_roles = len(cpp.roles) response = client.delete(f"/courses/{cpp.codename}/roles/{r.name}") assert response.status_code == 204 assert response.mimetype == 'application/json' cpp_updated = Course.query.filter_by(codename="PB161").first() assert len(cpp_updated.roles) == cpp_roles - 1 assert not Role.query.filter(Role.course_id == cpp.id).filter(Role.name == r_name).first() def test_users_list(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] response = client.get(f"/courses/{cpp.codename}/roles/{r.id}/users") assert response.status_code == 200 assert response.mimetype == 'application/json' users = json.loads(str(response.get_data().decode("utf-8"))) assert len(users) == len(r.users) for user in users: utils.assert_user_in(r.users, user) def test_users_update_add(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_users = len(r.users) user = User.query.filter_by(username="xbar").first() assert user not in r.users request_dict = dict( add=[user.id] ) request_json = json.dumps(request_dict) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert len(r_updated.users) == r_users + 1 assert user in r_updated.users def test_users_update_add_duplicate(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_users = len(r.users) user = r.users[0] assert user in r.users request_dict = dict( add=[user.id] ) request_json = json.dumps(request_dict) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert len(r_updated.users) == r_users assert user in r_updated.users def test_users_update_remove(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_users = len(r.users) user = r.users[0] assert user in r.users request_dict = dict( remove=[user.id] ) request_json = json.dumps(request_dict) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert len(r_updated.users) == r_users - 1 assert user not in r_updated.users def test_users_update_remove_user_not_in(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_users = len(r.users) user = User.query.filter_by(username="xbar").first() assert user not in r.users request_dict = dict( remove=[user.id] ) request_json = json.dumps(request_dict) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert len(r_updated.users) == r_users assert user not in r_updated.users def test_add_user(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] role_users = len(r.users) u = User.query.filter_by(username="xbar").first() assert not u.groups response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users/{u.username}") assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert u in r_updated.users assert len(r_updated.users) == role_users + 1 def test_add_user_duplicate(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] role_users = len(r.users) u = r.users[0] assert u in r.users response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users/{u.username}") assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert u in r_updated.users assert len(r_updated.users) == role_users def test_remove_user(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] role_users = len(r.users) u = r.users[0] response = client.delete(f"/courses/{cpp.codename}/roles/{r.name}/users/{u.username}") assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert u not in r_updated.users assert len(r_updated.users) == role_users - 1 def test_remove_user_not_in(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] role_users = len(r.users) u = User.query.filter_by(username="xbar").first() assert not u.groups response = client.delete(f"/courses/{cpp.codename}/roles/{r.name}/users/{u.username}") assert response.status_code == 400 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert u not in r_updated.users assert len(r_updated.users) == role_users def test_permissions_list(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] response = client.get(f"/courses/{cpp.codename}/roles/{r.name}/permissions") assert response.status_code == 200 assert response.mimetype == 'application/json' data = json.loads(str(response.get_data().decode("utf-8"))) utils.assert_role_permissions(r.permissions, data) def test_permissions_update(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_name = r.name request_dict = dict( viewCourseFull=True, writeRole=True, readAllSubmissions=True ) request_json = json.dumps(request_dict, cls=utils.DateTimeEncoder) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/permissions", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter_by(name=r_name).first() assert r_updated.permissions.viewCourseFull assert r_updated.permissions.writeRole assert r_updated.permissions.readAllSubmissions tests/rest/utils.py +43 −0 Original line number Diff line number Diff line Loading @@ -120,6 +120,49 @@ def assert_project_config(expected: ProjectConfig, actual: dict): assert expected.archive_from == actual['archive_from'] def assert_role_permissions(expected: Role, actual: dict): assert expected.id == actual['id'] assert expected.role.id == actual['role']['id'] assert expected.viewCourseLimited == actual['viewCourseLimited'] assert expected.viewCourseFull == actual['viewCourseFull'] assert expected.updateCourse == actual['updateCourse'] assert expected.setNotesAccessToken == actual['setNotesAccessToken'] assert expected.assignRoles == actual['assignRoles'] assert expected.writeRole == actual['writeRole'] assert expected.readRole == actual['readRole'] assert expected.writeProject == actual['writeProject'] assert expected.deleteProject == actual['deleteProject'] assert expected.archiveProject == actual['archiveProject'] assert expected.writeGroup == actual['writeGroup'] assert expected.readGroup == actual['readGroup'] assert expected.deleteGroup == actual['deleteGroup'] assert expected.readAllSubmissions == actual['readAllSubmissions'] assert expected.readOwnSubmissions == actual['readOwnSubmissions'] assert expected.readGroupSubmissions == actual['readGroupSubmissions'] assert expected.viewAllSubmissionFiles == actual['viewAllSubmissionFiles'] assert expected.createSubmission == actual['createSubmission'] assert expected.resubmitSubmission == actual['resubmitSubmission'] assert expected.readAllReviews == actual['readAllReviews'] assert expected.readOwnReviews == actual['readOwnReviews'] assert expected.writeOwnReview == actual['writeOwnReview'] assert expected.writeAllReview == actual['writeAllReview'] assert expected.evaluateSubmission == actual['evaluateSubmission'] def compare_role(expected: Role, actual: dict): return expected.id == actual['id'] \ and expected.name == actual['name'] \ and expected.description == actual['description'] \ and expected.course_id == actual['course']['id'] def assert_role_in(role_list: list, role: dict): for r in role_list: if compare_role(r, role): return True return False # source: https://stackoverflow.com/questions/11875770/how-to-overcome-datetime-datetime-not-json-serializable class DateTimeEncoder(json.JSONEncoder): def default(self, o): Loading Loading
portal/rest/__init__.py +1 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,7 @@ class RoleSchema(Schema): users = fields.Nested(UserSchema, only=('id', 'uco', 'email', 'username'), many=True) course = fields.Nested(CourseSchema, only=('id', 'name', 'codename')) # this could be done prettier (e.g. flattening the structure, showing only set fields) permissions = fields.Nested('portal.rest.RolePermissionsSchema', exclude=('id', 'role')) permissions = fields.Nested('portal.rest.RolePermissionsSchema') class RolePermissionsSchema(Schema): Loading
portal/rest/roles/roles.py +14 −11 Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ from flask import Blueprint, request from flask_restful import Api, Resource from portal.database.models import Role from portal.rest import role_schema, roles_schema, users_schema from portal.rest import role_schema, roles_schema, users_schema, user_list_update_schema, permissions_schema from portal.service import service from portal.service.errors import PortalAPIError from portal.tools.decorators import error_handler Loading Loading @@ -50,7 +50,6 @@ class RoleResource(Resource): class RoleList(Resource): @error_handler def get(self, cid): log.info(f"GET to {request.url}") Loading Loading @@ -80,7 +79,7 @@ class RolePermissions(Resource): log.info(f"GET to {request.url}") course = service.find_course(cid) role = service.find_role(course, rid) return roles_schema.dump(role.permissions) return permissions_schema.dump(role.permissions) @error_handler def put(self, cid, rid): Loading @@ -92,7 +91,7 @@ class RolePermissions(Resource): if not json_data: raise PortalAPIError(400, message='No data provided for update of role permissions.') data = role_schema.load(json_data)[0] data = permissions_schema.load(json_data)[0] role.set_permissions(**data) log.debug(f"Updated permissions for role {rid} in course {cid} to {data}.") Loading @@ -115,18 +114,22 @@ class RoleUsersList(Resource): role = service.find_role(course, rid) json_data = request.get_json() data = users_schema.load(json_data)[0] data = user_list_update_schema.load(json_data)[0] # TODO: use ids, move to service? # everything from users_add is added, THEN everything from users_remove is subtracted users_old = set(role.users) users_add = data.get('add') users_remove = data.get('remove') if users_add is not None: users_old.union(users_add) if users_remove is not None: users_old.difference(users_remove) users = set() if users_add: to_add = service.find_users(data['add']) users = users_old.union(to_add) if users_remove: to_remove = service.find_users(data['remove']) users = users_old.difference(to_remove) role.users = list(users) service.write_entity(role) log.info(f"Updated users of role {rid} to {data}.") return '', 204 Loading
tests/rest/test_project.py +1 −6 Original line number Diff line number Diff line Loading @@ -2,16 +2,11 @@ from datetime import timedelta from flask_jwt_extended import create_access_token from portal.database.models import Group, Course, User, Role, Project from portal.database.models import Course, User, Project from tools.time import NOW, strip_seconds, portal_timezone from . import utils import json ''' * `[POST] /courses/<cid>/projects/<pid>/submissions` : Create submission ''' def test_list(client): cpp = Course.query.filter_by(codename="PB161").first() Loading
tests/rest/test_role.py 0 → 100644 +286 −0 Original line number Diff line number Diff line from portal.database.models import Course, Role, User from . import utils import json def test_list(client): cpp = Course.query.filter_by(codename="PB161").first() cpp_roles = len(cpp.roles) response = client.get(f'/courses/{cpp.codename}/roles/') assert response.status_code == 200 assert response.mimetype == 'application/json' roles = json.loads(str(response.get_data().decode("utf-8"))) assert len(roles) == cpp_roles cpp_updated = Course.query.filter_by(codename="PB161").first() for r in roles: utils.assert_role_in(cpp_updated.roles, r) def test_create(client): cpp = Course.query.filter_by(codename="PB161").first() cpp_roles = len(cpp.roles) request_dict = { "name": "assistant", "description": "teacher assistant" } request_json = json.dumps(request_dict) response = client.post(f"/courses/{cpp.codename}/roles/", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 201 assert response.mimetype == 'application/json' new_role = json.loads(str(response.get_data().decode("utf-8"))) cpp_updated = Course.query.filter_by(codename="PB161").first() assert len(cpp_updated.roles) == cpp_roles + 1 assert new_role['name'] == "assistant" assert new_role['description'] == "teacher assistant" assert new_role['id'] utils.assert_role_in(cpp_updated.roles, new_role) def test_read(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] response = client.get(f"/courses/{cpp.codename}/roles/{r.name}") assert response.status_code == 200 assert response.mimetype == 'application/json' role = json.loads(str(response.get_data().decode("utf-8"))) utils.assert_role(r, role) def test_update(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_name = r.name request_dict = dict( name="new role name", description="new role desc", ) request_json = json.dumps(request_dict) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.name == "new role name").first() assert r_updated assert r_updated.description == "new role desc" assert not Role.query.filter(Role.course_id == cpp.id).filter(Role.name == r_name).first() def test_delete(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_name = r.name cpp_roles = len(cpp.roles) response = client.delete(f"/courses/{cpp.codename}/roles/{r.name}") assert response.status_code == 204 assert response.mimetype == 'application/json' cpp_updated = Course.query.filter_by(codename="PB161").first() assert len(cpp_updated.roles) == cpp_roles - 1 assert not Role.query.filter(Role.course_id == cpp.id).filter(Role.name == r_name).first() def test_users_list(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] response = client.get(f"/courses/{cpp.codename}/roles/{r.id}/users") assert response.status_code == 200 assert response.mimetype == 'application/json' users = json.loads(str(response.get_data().decode("utf-8"))) assert len(users) == len(r.users) for user in users: utils.assert_user_in(r.users, user) def test_users_update_add(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_users = len(r.users) user = User.query.filter_by(username="xbar").first() assert user not in r.users request_dict = dict( add=[user.id] ) request_json = json.dumps(request_dict) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert len(r_updated.users) == r_users + 1 assert user in r_updated.users def test_users_update_add_duplicate(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_users = len(r.users) user = r.users[0] assert user in r.users request_dict = dict( add=[user.id] ) request_json = json.dumps(request_dict) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert len(r_updated.users) == r_users assert user in r_updated.users def test_users_update_remove(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_users = len(r.users) user = r.users[0] assert user in r.users request_dict = dict( remove=[user.id] ) request_json = json.dumps(request_dict) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert len(r_updated.users) == r_users - 1 assert user not in r_updated.users def test_users_update_remove_user_not_in(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_users = len(r.users) user = User.query.filter_by(username="xbar").first() assert user not in r.users request_dict = dict( remove=[user.id] ) request_json = json.dumps(request_dict) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert len(r_updated.users) == r_users assert user not in r_updated.users def test_add_user(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] role_users = len(r.users) u = User.query.filter_by(username="xbar").first() assert not u.groups response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users/{u.username}") assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert u in r_updated.users assert len(r_updated.users) == role_users + 1 def test_add_user_duplicate(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] role_users = len(r.users) u = r.users[0] assert u in r.users response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/users/{u.username}") assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert u in r_updated.users assert len(r_updated.users) == role_users def test_remove_user(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] role_users = len(r.users) u = r.users[0] response = client.delete(f"/courses/{cpp.codename}/roles/{r.name}/users/{u.username}") assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert u not in r_updated.users assert len(r_updated.users) == role_users - 1 def test_remove_user_not_in(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] role_users = len(r.users) u = User.query.filter_by(username="xbar").first() assert not u.groups response = client.delete(f"/courses/{cpp.codename}/roles/{r.name}/users/{u.username}") assert response.status_code == 400 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter(Role.id == r.id).first() assert u not in r_updated.users assert len(r_updated.users) == role_users def test_permissions_list(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] response = client.get(f"/courses/{cpp.codename}/roles/{r.name}/permissions") assert response.status_code == 200 assert response.mimetype == 'application/json' data = json.loads(str(response.get_data().decode("utf-8"))) utils.assert_role_permissions(r.permissions, data) def test_permissions_update(client): cpp = Course.query.filter_by(codename="PB161").first() r = cpp.roles[0] r_name = r.name request_dict = dict( viewCourseFull=True, writeRole=True, readAllSubmissions=True ) request_json = json.dumps(request_dict, cls=utils.DateTimeEncoder) response = client.put(f"/courses/{cpp.codename}/roles/{r.name}/permissions", data=request_json, headers={"content-type": "application/json"}) assert response.status_code == 204 assert response.mimetype == 'application/json' r_updated = Role.query.filter(Role.course_id == cpp.id).filter_by(name=r_name).first() assert r_updated.permissions.viewCourseFull assert r_updated.permissions.writeRole assert r_updated.permissions.readAllSubmissions
tests/rest/utils.py +43 −0 Original line number Diff line number Diff line Loading @@ -120,6 +120,49 @@ def assert_project_config(expected: ProjectConfig, actual: dict): assert expected.archive_from == actual['archive_from'] def assert_role_permissions(expected: Role, actual: dict): assert expected.id == actual['id'] assert expected.role.id == actual['role']['id'] assert expected.viewCourseLimited == actual['viewCourseLimited'] assert expected.viewCourseFull == actual['viewCourseFull'] assert expected.updateCourse == actual['updateCourse'] assert expected.setNotesAccessToken == actual['setNotesAccessToken'] assert expected.assignRoles == actual['assignRoles'] assert expected.writeRole == actual['writeRole'] assert expected.readRole == actual['readRole'] assert expected.writeProject == actual['writeProject'] assert expected.deleteProject == actual['deleteProject'] assert expected.archiveProject == actual['archiveProject'] assert expected.writeGroup == actual['writeGroup'] assert expected.readGroup == actual['readGroup'] assert expected.deleteGroup == actual['deleteGroup'] assert expected.readAllSubmissions == actual['readAllSubmissions'] assert expected.readOwnSubmissions == actual['readOwnSubmissions'] assert expected.readGroupSubmissions == actual['readGroupSubmissions'] assert expected.viewAllSubmissionFiles == actual['viewAllSubmissionFiles'] assert expected.createSubmission == actual['createSubmission'] assert expected.resubmitSubmission == actual['resubmitSubmission'] assert expected.readAllReviews == actual['readAllReviews'] assert expected.readOwnReviews == actual['readOwnReviews'] assert expected.writeOwnReview == actual['writeOwnReview'] assert expected.writeAllReview == actual['writeAllReview'] assert expected.evaluateSubmission == actual['evaluateSubmission'] def compare_role(expected: Role, actual: dict): return expected.id == actual['id'] \ and expected.name == actual['name'] \ and expected.description == actual['description'] \ and expected.course_id == actual['course']['id'] def assert_role_in(role_list: list, role: dict): for r in role_list: if compare_role(r, role): return True return False # source: https://stackoverflow.com/questions/11875770/how-to-overcome-datetime-datetime-not-json-serializable class DateTimeEncoder(json.JSONEncoder): def default(self, o): Loading