import uuid from django.conf import settings from django.contrib.auth.models import Group as AuthGroup from django.contrib.auth.models import Permission from django.db import models from pirates import models as pirates_models class Group: def save(self, *args, **kwargs): for user in self.user_set.all(): if user.update_group_based_admin(): user.save() return super().save(*args, **kwargs) class Meta: proxy = True class User(pirates_models.AbstractUser): preferred_username = models.CharField( max_length=64, verbose_name="Username v Chobotnici", blank=True, null=True, ) sso_id = models.CharField( "SSO ID", max_length=128, ) is_staff_based_on_group = models.BooleanField( default=True, verbose_name="Administrační přístup dle členství ve skupině", help_text=( 'Určuje, zda bude "Administrační přístup" uživatele ' "definován dle členství ve skupinách, nebo podle " "speciálního nastavení zde." ), ) USERNAME_FIELD = "preferred_username" @property def can_approve_contracts(self) -> bool: return self.has_perm("contracts.approve") @property def can_create_contracts(self) -> bool: return self.has_perm("contracts.add_contract") @property def can_view_confidential(self) -> bool: return self.has_perm("contracts.view_confidential") @property def contracts_to_approve_count(self) -> int: if not self.can_approve_contracts: return 0 from contracts.models import Contract return Contract.objects.filter(status=Contract.StatusTypes.TO_BE_APPROVED).count() # https://docs.djangoproject.com/en/4.1/ref/models/instances/#customizing-model-loading @classmethod def from_db(cls, db, field_names, values): # Default implementation of from_db() (subject to change and could # be replaced with super()). if len(values) != len(cls._meta.concrete_fields): values = list(values) values.reverse() values = [ values.pop() if f.attname in field_names else models.DEFERRED for f in cls._meta.concrete_fields ] instance = cls(*values) instance._state.adding = False instance._state.db = db # customization to store the original field values on the instance instance._loaded_values = dict( zip( field_names, (value for value in values if value is not models.DEFERRED) ) ) return instance def set_unusable_password(self) -> None: # Purely for compatibility with Guardian pass def get_username(self) -> str: first_name = self.first_name if len(first_name) != 0: first_name += " " return f"{first_name}{self.last_name}" def get_all_permissions_ordered(self, obj=None) -> list: if not self.is_superuser: permissions = ( Permission.objects.filter( models.Q(group__user=self) | models.Q(user=self) ) .order_by("content_type__app_label") .distinct() .all() ) else: permissions = Permission.objects.order_by("content_type__app_label").all() return permissions def save(self, *args, saved_by_auth: bool = False, **kwargs): if ( not self._state.adding and not saved_by_auth and self._loaded_values["is_staff"] != self.is_staff ): self.is_staff_based_on_group = False return super().save(*args, **kwargs) def update_group_based_admin(self) -> bool: """ Updates this user's `is_staff` attribute based on whether or not one of their groups has default access to the admin interface. Returns whether or not any changes have been made. """ if not self.is_staff_based_on_group: return False self.is_staff_based_on_group = True is_staff = self.groups.filter(name__in=settings.DEFAULT_STAFF_GROUPS).exists() changes_made = False if is_staff is not self.is_staff: changes_made = True self.is_staff = is_staff return changes_made class Meta: app_label = "users" verbose_name = "Uživatel" verbose_name_plural = "Uživatelé"