schon/vibes_auth/models.py

168 lines
5.9 KiB
Python

from uuid import uuid4
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import Group as BaseGroup
from django.core.cache import cache
from django.db.models import (
BooleanField,
CharField,
EmailField,
ImageField,
JSONField,
UUIDField,
)
from django.utils.translation import gettext_lazy as _
from rest_framework_simplejwt.token_blacklist.models import (
BlacklistedToken as BaseBlacklistedToken,
)
from rest_framework_simplejwt.token_blacklist.models import (
OutstandingToken as BaseOutstandingToken,
)
from core.abstract import NiceModel
from evibes.settings import LANGUAGE_CODE, LANGUAGES
from vibes_auth.managers import UserManager
from vibes_auth.validators import validate_phone_number
class User(AbstractUser, NiceModel): # type: ignore [django-manager-missing]
__doc__ = _(
"Represents a User entity with customized fields and methods for extended functionality. " # type: ignore
"This class extends the AbstractUser model and integrates additional features like "
"custom email login, validation methods, subscription status, verification, and "
"attributes storage. It also provides utilities for managing recently viewed items and "
"token-based activation for verifying accounts. The User model is designed to handle "
"specific use cases for enhanced user management."
)
def get_uuid_as_path(self, *args):
return "users/" + str(self.uuid) + "/" + args[0]
email = EmailField(_("email"), unique=True, help_text=_("user email address"))
phone_number = CharField(
_("phone_number"),
max_length=20,
unique=True,
blank=True,
null=True,
help_text=_("user phone number"),
validators=[
validate_phone_number,
],
)
username: None = None # type: ignore [assignment]
first_name = CharField(_("first_name"), max_length=150, blank=True, null=True) # type: ignore [assignment]
last_name = CharField(_("last_name"), max_length=150, blank=True, null=True) # type: ignore [assignment]
avatar = ImageField(
null=True,
verbose_name=_("avatar"),
upload_to=get_uuid_as_path,
blank=True,
help_text=_("user profile image"),
)
is_verified = BooleanField(
default=False,
verbose_name=_("is verified"),
help_text=_("user verification status"),
)
is_active = BooleanField(
_("is_active"),
default=False,
help_text=_("unselect this instead of deleting accounts"),
)
is_subscribed = BooleanField(
verbose_name=_("is_subscribed"), help_text=_("user's newsletter subscription status"), default=False
)
activation_token = UUIDField(default=uuid4, verbose_name=_("activation token"))
language = CharField(choices=LANGUAGES, default=LANGUAGE_CODE, null=False, blank=False, max_length=7)
attributes = JSONField(verbose_name=_("attributes"), default=dict, blank=True, null=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
# noinspection PyClassVar
objects = UserManager() # type: ignore [misc, assignment]
def add_to_recently_viewed(self, product_uuid):
recently_viewed = self.recently_viewed
if product_uuid not in recently_viewed:
if not len(recently_viewed) >= 48:
recently_viewed.append(product_uuid)
cache.set(f"user_{self.uuid}_rv", recently_viewed)
else:
recently_viewed.pop(0)
recently_viewed.append(product_uuid)
cache.set(f"user_{self.uuid}_rv", recently_viewed)
@property
def recently_viewed(self):
return cache.get(f"user_{self.uuid}_rv", [])
def check_token(self, token):
return str(token) == str(self.activation_token)
def __str__(self):
return self.email
class Meta:
swappable = "AUTH_USER_MODEL"
verbose_name = _("user")
verbose_name_plural = _("users")
class Group(BaseGroup):
"""
Proxy model representing a Group entity.
This class acts as a proxy for the `BaseGroup` model, providing additional
configuration for display and usage purposes. It does not introduce new fields
or behavior but alters representation and metadata for the Group model.
Attributes:
Meta.proxy (bool): Indicates this is a proxy model.
Meta.verbose_name (str): Human-readable singular name for the Group model.
Meta.verbose_name_plural (str): Human-readable plural name for the Group
model.
"""
class Meta:
proxy = True
verbose_name = _("group")
verbose_name_plural = _("groups")
class OutstandingToken(BaseOutstandingToken):
"""
Represents a proxy model for outstanding tokens.
This class is a proxy for the `BaseOutstandingToken` model, used to manage
and customize behaviors or configurations related to outstanding tokens.
It does not add additional fields or logic to the base model but allows for
overloading or extending its default functionality as required.
"""
class Meta:
proxy = True
verbose_name = _("outstanding token")
verbose_name_plural = _("outstanding tokens")
class BlacklistedToken(BaseBlacklistedToken):
"""
Represents a blacklisted token model in the system.
This class acts as a Django model proxy and serves the purpose of managing
blacklisted tokens. It inherits from a base class provided for this purpose,
allowing for the extension of functionality or customization of behavior
without altering the original base class's structure. It also defines the
Meta options for the model, affecting its database and administrative
representation.
"""
class Meta:
proxy = True
verbose_name = _("blacklisted token")
verbose_name_plural = _("blacklisted tokens")