From 9c2728a9aa5eddaecc4eed218c48214736be4cc3 Mon Sep 17 00:00:00 2001 From: AndreiMPopescu Date: Fri, 22 Feb 2019 14:19:31 +0000 Subject: [PATCH 1/2] EF2E-1 Coaches create learner (without proper permissions) --- kolibri/core/auth/models.py | 3 ++ kolibri/core/auth/permissions/general.py | 47 ++++++++++++++++ .../coach/assets/src/modules/pluginModule.js | 2 + .../coach/assets/src/views/ClassListPage.vue | 6 +-- .../views/reports/CoachUserCreateModal.vue | 53 +++++++++++++++++-- .../src/views/reports/LearnerListPage.vue | 14 ++++- 6 files changed, 116 insertions(+), 9 deletions(-) diff --git a/kolibri/core/auth/models.py b/kolibri/core/auth/models.py index 5b9a6d485a7..3b971d82ba7 100644 --- a/kolibri/core/auth/models.py +++ b/kolibri/core/auth/models.py @@ -64,6 +64,7 @@ from .permissions.general import IsFromSameFacility from .permissions.general import IsOwn from .permissions.general import IsSelf +from .permissions.general import AllowCoach from kolibri.core.auth.constants.morango_scope_definitions import FULL_FACILITY from kolibri.core.auth.constants.morango_scope_definitions import SINGLE_USER from kolibri.core.errors import KolibriValidationError @@ -522,6 +523,7 @@ class FacilityUser(KolibriAbstractBaseUser, AbstractFacilityDataModel): permissions = ( IsSelf() | # FacilityUser can be read and written by itself IsAdminForOwnFacility() | # FacilityUser can be read and written by a facility admin + AllowCoach() | RoleBasedPermissions( # FacilityUser can be read by admin or coach, and updated by admin, but not created/deleted by non-facility admin target_field=".", can_be_created_by=(), # we can't check creation permissions by role, as user doesn't exist yet @@ -903,6 +905,7 @@ class Membership(AbstractFacilityDataModel): morango_model_name = "membership" permissions = ( + AllowCoach() | IsOwn(read_only=True) | # users can read their own Memberships RoleBasedPermissions( # Memberships can be read and written by admins, and read by coaches, for the member user target_field="user", diff --git a/kolibri/core/auth/permissions/general.py b/kolibri/core/auth/permissions/general.py index 356e0aa9280..88e44fbf543 100644 --- a/kolibri/core/auth/permissions/general.py +++ b/kolibri/core/auth/permissions/general.py @@ -180,3 +180,50 @@ def readable_by_user_filter(self, user, queryset): return queryset.filter(dataset=user.dataset) else: return queryset.none() + + +class AllowCoach(BasePermissions): + + def __init__(self, field_name=".", read_only=False): + self.read_only = read_only + + def _user_is_coach(self, user, obj=None): + + from ..models import Classroom + + # if obj: + # if not hasattr(obj, "dataset") or not user.dataset == obj.dataset: + # return False + # + # classrooms = Classroom.objects.filter(dataset=user.dataset) + # + # is_coach = 0 + # + # for classroom in classrooms: + # if user.has_role_for_collection(role_kinds.COACH, classroom): + # is_coach += 1 + # + # return is_coach > 0 + + return True + + + + def user_can_create_object(self, user, obj): + return (not self.read_only) and self._user_is_coach(user, obj) + + def user_can_read_object(self, user, obj): + return self._user_is_coach(user, obj) + + def user_can_update_object(self, user, obj): + return (not self.read_only) and self._user_is_coach(user, obj) + + def user_can_delete_object(self, user, obj): + return (not self.read_only) and self._user_is_coach(user, obj) + + def readable_by_user_filter(self, user, queryset): + if self._user_is_coach(user): + return queryset.filter(dataset=user.dataset) + else: + return queryset.none() + diff --git a/kolibri/plugins/coach/assets/src/modules/pluginModule.js b/kolibri/plugins/coach/assets/src/modules/pluginModule.js index 855c0f6bb1c..61aa231f60d 100644 --- a/kolibri/plugins/coach/assets/src/modules/pluginModule.js +++ b/kolibri/plugins/coach/assets/src/modules/pluginModule.js @@ -1,4 +1,5 @@ import userManagement from '../../../../facility_management/assets/src/modules/userManagement'; +import classAssignMembers from '../../../../facility_management/assets/src/modules/classAssignMembers'; import getters from './coreCoach/getters'; import * as actions from './coreCoach/actions'; import examCreation from './examCreation'; @@ -56,6 +57,7 @@ export default { lessonSummary, lessonsRoot, userManagement, + classAssignMembers, reports, }, }; diff --git a/kolibri/plugins/coach/assets/src/views/ClassListPage.vue b/kolibri/plugins/coach/assets/src/views/ClassListPage.vue index 1b2f36ab4cf..0af42e5409f 100644 --- a/kolibri/plugins/coach/assets/src/views/ClassListPage.vue +++ b/kolibri/plugins/coach/assets/src/views/ClassListPage.vue @@ -43,7 +43,7 @@ @@ -84,10 +84,10 @@ import { PageNames } from '../constants'; import { filterAndSortUsers } from '../../../../facility_management/assets/src/userSearchUtils'; - function learnerPageLink(classId) { + function learnerPageLink(classId, className) { return { name: PageNames.LEARNER_LIST, - params: { classId }, + params: { classId, className }, }; } diff --git a/kolibri/plugins/coach/assets/src/views/reports/CoachUserCreateModal.vue b/kolibri/plugins/coach/assets/src/views/reports/CoachUserCreateModal.vue index b5281365409..4debffebd11 100644 --- a/kolibri/plugins/coach/assets/src/views/reports/CoachUserCreateModal.vue +++ b/kolibri/plugins/coach/assets/src/views/reports/CoachUserCreateModal.vue @@ -1,7 +1,7 @@