Features: 1) Add RecentProductConnection to support recently viewed products in GraphQL; 2) Implement recently_viewed field in UserType with reverse-chronological product ordering; 3) Add recently_viewed field to UserSerializer and return data with ProductSimpleSerializer.
Fixes: 1) Fix `resolve_recently_viewed` to handle empty UUIDs and avoid breaking queries. Extra: Refactor imports in `graphene/object_types.py` and `serializers.py` for better clarity; Adjust minor formatting in `TokenObtainSerializer`.
This commit is contained in:
parent
f76b000e07
commit
89f6594751
2 changed files with 37 additions and 6 deletions
|
|
@ -3,8 +3,10 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from graphene import Field, List, String, relay
|
from graphene import Field, List, String, relay
|
||||||
from graphene.types.generic import GenericScalar
|
from graphene.types.generic import GenericScalar
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
|
from graphql_relay.connection.array_connection import connection_from_array
|
||||||
|
|
||||||
from core.graphene.object_types import OrderType, WishlistType
|
from core.graphene.object_types import OrderType, ProductType, WishlistType
|
||||||
|
from core.models import Product
|
||||||
from evibes.settings import LANGUAGE_CODE, LANGUAGES
|
from evibes.settings import LANGUAGE_CODE, LANGUAGES
|
||||||
from payments.graphene.object_types import BalanceType
|
from payments.graphene.object_types import BalanceType
|
||||||
from vibes_auth.models import User
|
from vibes_auth.models import User
|
||||||
|
|
@ -26,8 +28,16 @@ class PermissionType(DjangoObjectType):
|
||||||
filter_fields = ["name", "id"]
|
filter_fields = ["name", "id"]
|
||||||
|
|
||||||
|
|
||||||
|
class RecentProductConnection(relay.Connection):
|
||||||
|
class Meta:
|
||||||
|
node = ProductType
|
||||||
|
|
||||||
|
|
||||||
class UserType(DjangoObjectType):
|
class UserType(DjangoObjectType):
|
||||||
recently_viewed = GenericScalar(description=_("recently viewed products' UUIDs"))
|
recently_viewed = relay.ConnectionField(
|
||||||
|
RecentProductConnection,
|
||||||
|
description=_("the products this user has viewed most recently (max 48), in reverse‐chronological order"),
|
||||||
|
)
|
||||||
groups = List(lambda: GroupType, description=_("groups"))
|
groups = List(lambda: GroupType, description=_("groups"))
|
||||||
user_permissions = List(lambda: PermissionType, description=_("permissions"))
|
user_permissions = List(lambda: PermissionType, description=_("permissions"))
|
||||||
orders = List(lambda: OrderType, description=_("orders"))
|
orders = List(lambda: OrderType, description=_("orders"))
|
||||||
|
|
@ -89,8 +99,23 @@ class UserType(DjangoObjectType):
|
||||||
def resolve_orders(self, info):
|
def resolve_orders(self, info):
|
||||||
return self.orders.all() if self.orders.count() >= 1 else []
|
return self.orders.all() if self.orders.count() >= 1 else []
|
||||||
|
|
||||||
def resolve_recently_viewed(self, info):
|
def resolve_recently_viewed(self, info, **kwargs):
|
||||||
return [] or self.recently_viewed
|
uuid_list = self.recently_viewed or []
|
||||||
|
|
||||||
|
if not uuid_list:
|
||||||
|
return connection_from_array([], kwargs)
|
||||||
|
|
||||||
|
qs = Product.objects.filter(uuid__in=uuid_list)
|
||||||
|
|
||||||
|
products_by_uuid = {str(p.uuid): p for p in qs}
|
||||||
|
|
||||||
|
ordered_products = [
|
||||||
|
products_by_uuid[u]
|
||||||
|
for u in uuid_list
|
||||||
|
if u in products_by_uuid
|
||||||
|
]
|
||||||
|
|
||||||
|
return connection_from_array(ordered_products, kwargs)
|
||||||
|
|
||||||
def resolve_groups(self, info):
|
def resolve_groups(self, info):
|
||||||
return self.groups.all() if self.groups.count() >= 1 else []
|
return self.groups.all() if self.groups.count() >= 1 else []
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ from rest_framework_simplejwt.settings import api_settings
|
||||||
from rest_framework_simplejwt.token_blacklist.models import BlacklistedToken
|
from rest_framework_simplejwt.token_blacklist.models import BlacklistedToken
|
||||||
from rest_framework_simplejwt.tokens import RefreshToken, Token, UntypedToken
|
from rest_framework_simplejwt.tokens import RefreshToken, Token, UntypedToken
|
||||||
|
|
||||||
|
from core.models import Product
|
||||||
|
from core.serializers import ProductSimpleSerializer
|
||||||
from core.utils.security import is_safe_key
|
from core.utils.security import is_safe_key
|
||||||
from evibes import settings
|
from evibes import settings
|
||||||
from vibes_auth.models import User
|
from vibes_auth.models import User
|
||||||
|
|
@ -32,6 +34,7 @@ class UserSerializer(ModelSerializer):
|
||||||
avatar_url = SerializerMethodField(required=False, read_only=True)
|
avatar_url = SerializerMethodField(required=False, read_only=True)
|
||||||
password = CharField(write_only=True, required=False)
|
password = CharField(write_only=True, required=False)
|
||||||
is_staff = BooleanField(read_only=True)
|
is_staff = BooleanField(read_only=True)
|
||||||
|
recently_viewed = SerializerMethodField(required=False, read_only=True)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_avatar_url(obj) -> str:
|
def get_avatar_url(obj) -> str:
|
||||||
|
|
@ -84,6 +87,9 @@ class UserSerializer(ModelSerializer):
|
||||||
validate_password(attrs["password"])
|
validate_password(attrs["password"])
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
def get_recently_viewed(self, obj) -> ProductSimpleSerializer.data:
|
||||||
|
return ProductSimpleSerializer(Product.objects.filter(uuid__in=([] or obj.recently_viewed)), many=True).data
|
||||||
|
|
||||||
|
|
||||||
class TokenObtainSerializer(Serializer):
|
class TokenObtainSerializer(Serializer):
|
||||||
username_field = User.USERNAME_FIELD
|
username_field = User.USERNAME_FIELD
|
||||||
|
|
@ -177,8 +183,8 @@ class TokenVerifySerializer(Serializer):
|
||||||
token = UntypedToken(attrs["token"])
|
token = UntypedToken(attrs["token"])
|
||||||
|
|
||||||
if (
|
if (
|
||||||
api_settings.BLACKLIST_AFTER_ROTATION
|
api_settings.BLACKLIST_AFTER_ROTATION
|
||||||
and "rest_framework_simplejwt.token_blacklist" in settings.INSTALLED_APPS
|
and "rest_framework_simplejwt.token_blacklist" in settings.INSTALLED_APPS
|
||||||
):
|
):
|
||||||
jti = token.get(api_settings.JTI_CLAIM)
|
jti = token.get(api_settings.JTI_CLAIM)
|
||||||
if BlacklistedToken.objects.filter(token__jti=jti).exists():
|
if BlacklistedToken.objects.filter(token__jti=jti).exists():
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue