216 lines
8.4 KiB
Python
216 lines
8.4 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,
|
|
QuerySet,
|
|
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 core.models import Order, Wishlist
|
|
from evibes.settings import LANGUAGE_CODE, LANGUAGES
|
|
from payments.models import Balance
|
|
from vibes_auth.managers import UserManager
|
|
from vibes_auth.validators import validate_phone_number
|
|
|
|
|
|
class User(AbstractUser, NiceModel): # type: ignore [django-manager-missing]
|
|
"""
|
|
Represents a User entity with customized fields and methods for extended functionality.
|
|
|
|
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.
|
|
|
|
Attributes:
|
|
email: EmailField to store the user's email address.
|
|
phone_number: CharField for the user's phone number, allowing for optional storage and validation.
|
|
username: Has been set to None as email is the primary unique identifier.
|
|
first_name: Optional CharField for the user's first name.
|
|
last_name: Optional CharField for the user's last name.
|
|
avatar: ImageField for storing the path to the user's profile picture.
|
|
is_verified: BooleanField indicating whether the user's email has been verified.
|
|
is_active: BooleanField to toggle user activity without deleting the account.
|
|
is_subscribed: BooleanField indicating the user's newsletter subscription status.
|
|
activation_token: UUIDField for assigning a unique activation token to the user.
|
|
language: CharField storing the user's preferred language setting.
|
|
attributes: JSONField for custom storage of user-specific additional attributes.
|
|
USERNAME_FIELD: Specifies the unique identifier for the user (email in this case).
|
|
REQUIRED_FIELDS: A list of fields required when creating a user via createsuperuser, left empty here.
|
|
objects: Custom manager for the User model providing additional methods for user creation.
|
|
payments_balance: Reference to the user's payment balance (related to the external model).
|
|
user_related_wishlist: Reference to the user's wishlist (related to the external model).
|
|
orders: QuerySet representing the user's associated orders.
|
|
|
|
Methods:
|
|
add_to_recently_viewed(product_uuid):
|
|
Adds a product's UUID to the user's recently viewed items cache. Keeps a maximum
|
|
of 48 items and maintains their order of viewing.
|
|
|
|
recently_viewed: (read-only property)
|
|
Retrieves a list of UUIDs representing the products recently viewed by the user
|
|
from the cache.
|
|
|
|
check_token(token):
|
|
Validates the input token against the user's activation token.
|
|
|
|
__str__():
|
|
Returns the string representation of the user, which is the email address.
|
|
|
|
Meta:
|
|
swappable: Configures the model to be replaceable with another user model.
|
|
verbose_name: Sets the human-readable name for singular instances of the model.
|
|
verbose_name_plural: Sets the human-readable name for multiple instances of the model.
|
|
"""
|
|
|
|
def get_uuid_as_path(self, *args):
|
|
return 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]
|
|
|
|
payments_balance: "Balance"
|
|
user_related_wishlist: "Wishlist"
|
|
orders: QuerySet["Order"]
|
|
|
|
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")
|