import secrets import string from typing import Optional from django.conf import settings from django.contrib.auth import get_user_model from django.db import models from django.utils.translation import gettext_lazy as _ from phonenumber_field.modelfields import PhoneNumberField from rules import is_superuser from rules.contrib.models import RulesModel from members.rules import is_member_manager class MemberManager(models.Manager): def get_queryset(self) -> models.QuerySet: return super().get_queryset().select_related("user") class Member(RulesModel): user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="member", verbose_name=_("user")) family_members = models.ManyToManyField("self", symmetrical=True, blank=True, verbose_name=_("family members")) birthday = models.DateField(_("birthday"), blank=True, null=True) license = models.CharField(_("license"), max_length=20, blank=True, null=True) phone_number = PhoneNumberField(_("phone number"), blank=True, null=True) emergency_phone_number = PhoneNumberField(_("emergency phone number"), blank=True, null=True) notes = models.TextField(_("notes"), blank=True, null=True) access_token = models.CharField(_("access token"), max_length=255, blank=True, null=True) created = models.DateTimeField(auto_now_add=True, verbose_name=_("created")) updated = models.DateTimeField(auto_now=True, verbose_name=_("updated")) objects = MemberManager() class Meta: verbose_name = _("member") verbose_name_plural = _("members") ordering = ["user__last_name", "user__first_name"] permissions = [("member_manager", _("Can manage members"))] rules_permissions = { "add": is_superuser | is_member_manager, "change": is_superuser | is_member_manager, "delete": is_superuser | is_member_manager, "view": is_superuser | is_member_manager, } def __str__(self): return self.user.get_full_name() @classmethod def create(cls, first_name: str, last_name: str, email: str, password: Optional[str] = None, member: Optional["Member"] = None) -> "Member": """Creates a new member based on the provided details""" if member is not None and member.pk is not None: member.user.first_name = first_name member.user.last_name = last_name member.user.email = email member.user.username = email if password is not None and password != "": member.user.set_password(password) else: # First check to see if a user already exists in the system user, created = get_user_model().objects.get_or_create( username=email, defaults={ "first_name": first_name, "last_name": last_name, "email": email } ) if not created: user.first_name = first_name user.last_name = last_name user.email = email user.username = email if hasattr(user, "member"): member = user.member if password is not None and password != "": user.set_password(password) else: member = cls() initial_password = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(20)) if password is None or password == "": password = initial_password member.notes = f"Initial password: {initial_password}" user.set_password(password) member.user = user if not member.user.is_active: member.user.is_active = True member.user.save() member.save() return member