from django.contrib.auth import get_user_model from django.contrib.auth.models import AbstractUser, Permission from django.contrib.contenttypes.models import ContentType from django.core.validators import MinValueValidator, MaxValueValidator from django.db import models from django.db.models import Q from django.utils.translation import ugettext_lazy as _ DEFAULT_SCHOOL_ID = 1 class User(AbstractUser): def get_school_permissions(self, school): perms = set() for role in SchoolRole.objects.get_school_roles_for_user(self): perms = perms.union( ('{}.{}'.format(r.content_type.app_label, r.codename) for r in role.role_permission.all()) ) return perms def get_all_permissions(self, obj=None): """ works as long as we have only a single school :param obj: :return: django permissions and school permissions for single default school """ django_permissions = super().get_all_permissions(obj) return django_permissions.union(self.get_school_permissions(School.objects.get(pk=DEFAULT_SCHOOL_ID))) class School(models.Model): name = models.CharField(_(u'Name'), max_length=100, null=False, blank=False) @classmethod def create_school(cls, name, id=None): school = School(name=name, id=id) school.save() # Label.create_labels_for_school(school) SchoolRole.objects.create_default_roles_for_school(school) return school def __str__(self): return self.name class SchoolClass(models.Model): name = models.CharField(max_length=100, blank=False, null=False) year = models.PositiveIntegerField(blank=False, null=False, validators=[MinValueValidator(1900), MaxValueValidator(2200)]) is_deleted = models.BooleanField(blank=False, null=False, default=False) users = models.ManyToManyField(get_user_model(), related_name='school_classes') school = models.ForeignKey('School', null=False, on_delete=models.CASCADE) def __str__(self): return 'SchoolClass {}-{}-{}'.format(self.id, self.name, self.year) class SchoolRoleManager(models.Manager): use_in_migrations = True TEACHER_KEY = 'teacher' STUDENT_KEY = 'student' PARENT_KEY = 'parent' SCHOOL_ADMIN_KEY = 'school_admin' DEFAULT_ROLES = { TEACHER_KEY: _(u'Lehrperson'), STUDENT_KEY: _(u'Schüler'), # PARENT_KEY: _(u'Aufsichtsperson'), # SCHOOL_ADMIN_KEY: _(u'Schuladministrator') } READONLY_ROLES = [SCHOOL_ADMIN_KEY] DEFAULT_ROLE_KEYS = DEFAULT_ROLES.keys() def is_key_in_defaults(self, key): return key in self.DEFAULT_ROLE_KEYS def is_key_readonly(self, key): return key in self.READONLY_ROLES def get_school_roles_for_user(self, hc_user): return self.model.objects.filter(userschoolrole__user=hc_user) def create_default_roles_for_school(self, school): for key, value in self.DEFAULT_ROLES.items(): role = self.create(name=value, school=school, key=key) role.save() can_manage_school_class_content, = self._create_default_permissions() if key == "teacher": role.role_permission.add(can_manage_school_class_content.id) # elif key == "school_admin": # role.role_permission.add() # # elif key == "student": # role.role_permission.add() def get_default_admin_role_for_school(self, school): return self._get_default_role_for_school(school, self.SCHOOL_ADMIN_KEY) def get_default_teacher_role_for_school(self, school): return self._get_default_role_for_school(school, self.TEACHER_KEY) def get_default_student_role_for_school(self, school): return self._get_default_role_for_school(school, self.STUDENT_KEY) def get_default_parent_for_school(self, school): return self._get_default_role_for_school(school, self.PARENT_KEY) def _get_default_role_for_school(self, school, key): try: return self.get(school=school, name=self.DEFAULT_ROLES[key]) except self.model.DoesNotExist: return None def _create_default_permissions(self): content_type = ContentType.objects.get_for_model(self.model) #edit_events = Permission.objects.get(content_type=content_type, codename="can_edit_events") #edit_own_comments = Permission.objects.get(content_type=content_type, codename="can_edit_own_comments") #delete_comments = Permission.objects.get(content_type=content_type, codename="can_delete_comments") #admin_school = Permission.objects.get(content_type=content_type, codename="can_admin_school") can_manage_school_class_content = Permission.objects.get(content_type=content_type, codename='can_manage_school_class_content') return can_manage_school_class_content, class SchoolRole(models.Model): key = models.CharField(_('Key'), max_length=100, blank=False, null=False) name = models.CharField(_('Name'), max_length=100, blank=False, null=False) school = models.ForeignKey('School', blank=False, null=False, on_delete=models.CASCADE) role_permission = models.ManyToManyField(Permission, verbose_name=_('Role permission'), blank=True, related_name="role_set", related_query_name="role") objects = SchoolRoleManager() def __str__(self): return u'{} - {}'.format(self.school, self.name) def permissions_as_code(self): return self.role_permission.values_list('codename', flat=True) def has_permission(self, permission_name): try: self.role_permission.get(codename=permission_name) return True except Permission.DoesNotExist: return False @staticmethod def create_key(name): return name.lower() class Meta: permissions = ( # ("can_edit_events", "Can edit events"), # ("can_edit_own_comments", "Can edit own comments"), # ("can_delete_comments", "Can delete comments"), ('can_manage_school_class_content', 'Can manage contents for assigned school clases'), # ("can_admin_school", "Can admin school"), ) unique_together = ('key', 'school',) class UserSchoolRoleManager(models.Manager): def create_userrole_for_user_and_school(self, hc_user, school, role_key): try: school_role = SchoolRole.objects.get(school=school, key=role_key) except SchoolRole.DoesNotExist: return None return self._create_user_schoolrole(hc_user, school_role) def create_role_and_userrole_for_user_and_school(self, hc_user, school, role_name): created = False role_key = role_name.lower() try: school_role = SchoolRole.objects.get(school=school, name=role_name) except SchoolRole.DoesNotExist: school_role = SchoolRole(school=school, key=role_key, name=role_name) school_role.save() created = True return self._create_user_schoolrole(hc_user, school_role), created def _create_user_schoolrole(self, hc_user, school_role): user_school_role = self.model(user=hc_user, school_role=school_role) user_school_role.save() return user_school_role class UserSchoolRole(models.Model): user = models.ForeignKey(User, blank=False, null=False, on_delete=models.CASCADE) school_role = models.ForeignKey(SchoolRole, blank=False, null=False, on_delete=models.CASCADE) objects = UserSchoolRoleManager() @property def groups(self): return SchoolClass.objects.filter(Q(school_id=self.school_role.school.id) & Q(users=self.user.id)) @property def group_ids(self): return map(lambda g: g.id, self.groups) def addgroup(self, group): group.user_set.add(self.user.user) self.user.user.groups.add(group) self.user.user.save() @classmethod def get_roles_for_user(cls, user): roles = UserSchoolRole.objects.filter(user=user) return roles # TODO: This method is only valid as long as a user can only belong to one school (today's setup) @classmethod def get_role_for_user(cls, user): roles = UserSchoolRole.get_roles_for_user(user) if len(roles) > 0: return roles[0] else: return None def __str__(self): return '%s: %s' % (self.school_role, self.user)