272 lines
9.7 KiB
Python
272 lines
9.7 KiB
Python
import re
|
|
from datetime import datetime
|
|
import string
|
|
import random
|
|
|
|
from django.contrib.auth import get_user_model
|
|
from django.contrib.auth.models import AbstractUser, Permission
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
from django.db import models
|
|
from django.utils.translation import ugettext_lazy as _
|
|
|
|
from core.hep_client import HepClient, MYSKILLBOX_LICENSES
|
|
from users.managers import RoleManager, UserRoleManager, UserManager, LicenseManager
|
|
|
|
DEFAULT_SCHOOL_ID = 1
|
|
|
|
|
|
class User(AbstractUser):
|
|
last_module = models.ForeignKey('books.Module', related_name='+', on_delete=models.SET_NULL, null=True)
|
|
recent_modules = models.ManyToManyField('books.Module', related_name='+', through='books.RecentModule')
|
|
last_topic = models.ForeignKey('books.Topic', related_name='+', on_delete=models.SET_NULL, null=True)
|
|
avatar_url = models.CharField(max_length=254, blank=True, default='')
|
|
email = models.EmailField(_('email address'), unique=True)
|
|
hep_id = models.PositiveIntegerField(null=True, blank=False)
|
|
hep_group_id = models.PositiveIntegerField(null=True, blank=False)
|
|
license_expiry_date = models.DateField(blank=False, null=True, default=None)
|
|
onboarding_visited = models.BooleanField(default=False)
|
|
|
|
objects = UserManager()
|
|
|
|
def get_role_permissions(self):
|
|
perms = set()
|
|
for role in Role.objects.get_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_role_permissions())
|
|
|
|
def has_perm(self, perm, obj=None):
|
|
return super(User, self).has_perm(perm, obj) or perm in self.get_all_permissions(obj)
|
|
|
|
def users_in_same_school_class(self):
|
|
return User.objects.filter(school_classes__users=self.pk)
|
|
|
|
def get_teacher(self):
|
|
if self.is_teacher():
|
|
return self
|
|
elif self.school_classes.count() > 0:
|
|
return self.school_classes.first().get_teacher()
|
|
else:
|
|
return None
|
|
|
|
def is_teacher(self):
|
|
return self.user_roles.filter(role__key='teacher').exists()
|
|
|
|
def selected_class(self):
|
|
try:
|
|
settings = UserSetting.objects.get(user=self)
|
|
return settings.selected_class
|
|
except ObjectDoesNotExist:
|
|
if self.school_classes.count() > 0:
|
|
default_selected_class = self.school_classes.first()
|
|
UserSetting.objects.create(selected_class=default_selected_class, user=self)
|
|
return default_selected_class
|
|
else:
|
|
return None
|
|
|
|
def sync_with_hep_data(self, hep_data):
|
|
|
|
data_has_changed = False
|
|
|
|
if self.email != hep_data['email']:
|
|
self.email = hep_data['email']
|
|
self.username = hep_data['email']
|
|
data_has_changed = True
|
|
|
|
if self.first_name != hep_data['firstname']:
|
|
self.first_name = hep_data['firstname']
|
|
data_has_changed = True
|
|
|
|
if self.last_name != hep_data['lastname']:
|
|
self.last_name = hep_data['lastname']
|
|
data_has_changed = True
|
|
|
|
if data_has_changed:
|
|
self.save()
|
|
|
|
def set_selected_class(self, school_class):
|
|
user_settings, created = UserSetting.objects.get_or_create(user=self)
|
|
user_settings.selected_class = school_class
|
|
user_settings.save()
|
|
|
|
@property
|
|
def full_name(self):
|
|
return self.get_full_name()
|
|
|
|
|
|
class SchoolClass(models.Model):
|
|
name = models.CharField(max_length=100, blank=False, null=False, unique=True)
|
|
is_deleted = models.BooleanField(blank=False, null=False, default=False)
|
|
users = models.ManyToManyField(get_user_model(), related_name='school_classes', blank=True,
|
|
through='users.SchoolClassMember')
|
|
code = models.CharField('Code zum Beitreten', blank=True, null=True, max_length=10, unique=True, default=None)
|
|
|
|
class Meta:
|
|
verbose_name = 'Schulklasse'
|
|
verbose_name_plural = 'Schulklassen'
|
|
|
|
def __str__(self):
|
|
return '{}'.format(self.name)
|
|
|
|
@classmethod
|
|
def generate_default_group_name(cls, user=None):
|
|
prefix = 'Meine Klasse'
|
|
if user is not None:
|
|
return f'{prefix} {user.pk}'
|
|
prefix_regex = r'Meine Klasse (\d+)'
|
|
initial_default_group = '{} 1'.format(prefix)
|
|
my_group_filter = cls.objects.filter(name__startswith=prefix).order_by('-pk')
|
|
|
|
if len(my_group_filter) == 0:
|
|
return initial_default_group
|
|
|
|
match = re.search(prefix_regex, my_group_filter[0].name)
|
|
|
|
if not match:
|
|
return initial_default_group
|
|
|
|
index = int(match.group(1))
|
|
|
|
return '{} {}'.format(prefix, index + 1)
|
|
|
|
@classmethod
|
|
def create_default_group_for_teacher(cls, user):
|
|
default_class_name = cls.generate_default_group_name()
|
|
default_class = cls.objects.create(name=default_class_name)
|
|
SchoolClassMember.objects.create(
|
|
user=user,
|
|
school_class=default_class
|
|
)
|
|
|
|
def is_user_in_schoolclass(self, user):
|
|
return user.is_superuser or user.school_classes.filter(pk=self.id).count() > 0
|
|
|
|
def get_teacher(self):
|
|
return self.users.filter(user_roles__role__key='teacher').first()
|
|
|
|
def generate_code(self):
|
|
letters = string.ascii_lowercase
|
|
digits = string.digits
|
|
code = ''.join(random.choice(letters) for i in range(4)) + ''.join(random.choice(digits) for i in range(2))
|
|
try:
|
|
SchoolClass.objects.get(code=code)
|
|
self.generate_code()
|
|
except SchoolClass.DoesNotExist:
|
|
self.code = code.upper()
|
|
self.save()
|
|
|
|
def save(self, *args, **kwargs):
|
|
if self.code == '': # '' can't be unique, so we null it
|
|
self.code = None
|
|
super().save(*args, **kwargs)
|
|
|
|
|
|
class Role(models.Model):
|
|
key = models.CharField(_('Key'), max_length=100, blank=False, null=False, unique=True)
|
|
name = models.CharField(_('Name'), max_length=100, blank=False, null=False)
|
|
role_permission = models.ManyToManyField(Permission, verbose_name=_('Role permission'),
|
|
blank=True, related_name="role_set", related_query_name="role")
|
|
|
|
objects = RoleManager()
|
|
|
|
def __str__(self):
|
|
return 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"),
|
|
)
|
|
|
|
|
|
class UserRole(models.Model):
|
|
user = models.ForeignKey(User, blank=False, null=False, on_delete=models.CASCADE, related_name='user_roles')
|
|
role = models.ForeignKey(Role, blank=False, null=False, on_delete=models.CASCADE, related_name='user_roles')
|
|
|
|
objects = UserRoleManager()
|
|
|
|
@property
|
|
def groups(self):
|
|
return SchoolClass.objects.filter(users=self.user.id)
|
|
|
|
@property
|
|
def group_ids(self):
|
|
return map(lambda g: g.id, self.groups)
|
|
|
|
@classmethod
|
|
def get_roles_for_user(cls, user):
|
|
roles = UserRole.objects.filter(user=user)
|
|
return roles
|
|
|
|
@classmethod
|
|
def get_role_for_user(cls, user):
|
|
return UserRole.get_roles_for_user(user).first()
|
|
|
|
def __str__(self):
|
|
return '%s: %s' % (self.role, self.user)
|
|
|
|
|
|
class UserSetting(models.Model):
|
|
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, related_name='user_setting')
|
|
selected_class = models.ForeignKey(SchoolClass, blank=True, null=True, on_delete=models.CASCADE)
|
|
|
|
|
|
class UserData(models.Model):
|
|
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, related_name='user_data')
|
|
accepted_terms = models.BooleanField(default=False)
|
|
|
|
|
|
class License(models.Model):
|
|
for_role = models.ForeignKey(Role, blank=False, null=True, on_delete=models.CASCADE)
|
|
licensee = models.ForeignKey(User, blank=False, null=True, on_delete=models.CASCADE)
|
|
expire_date = models.DateField(blank=False, null=True, )
|
|
order_id = models.IntegerField(blank=False, null=False, default=-1)
|
|
raw = models.TextField(default='')
|
|
isbn = models.CharField(max_length=50, blank=False, null=False,
|
|
default=list(MYSKILLBOX_LICENSES.keys())[0]) # student license
|
|
|
|
objects = LicenseManager()
|
|
|
|
def is_teacher_license(self):
|
|
return self.for_role.key == RoleManager.TEACHER_KEY
|
|
|
|
def is_valid(self):
|
|
return HepClient.is_product_active(
|
|
datetime(self.expire_date.year, self.expire_date.month, self.expire_date.day), self.isbn)
|
|
|
|
def __str__(self):
|
|
return f'License for role: {self.for_role}'
|
|
|
|
|
|
class SchoolClassMember(models.Model):
|
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
|
school_class = models.ForeignKey(SchoolClass, on_delete=models.CASCADE)
|
|
active = models.BooleanField(default=True)
|