diff --git a/core/graphene/object_types.py b/core/graphene/object_types.py index 8cd928e6..41d7566f 100644 --- a/core/graphene/object_types.py +++ b/core/graphene/object_types.py @@ -554,7 +554,7 @@ class ProductType(DjangoObjectType): description = (self.description or "")[:180] first_img = self.images.order_by("priority").first() - og_image = _abs(info.context, first_img.image.url) if first_img else "" + og_image = graphene_abs(info.context, first_img.image.url) if first_img else "" og = { "title": title, diff --git a/core/permissions.py b/core/permissions.py index a462229b..ff1f9c92 100644 --- a/core/permissions.py +++ b/core/permissions.py @@ -47,6 +47,9 @@ class EvibesPermission(permissions.BasePermission): app_label = model._meta.app_label model_name = model._meta.model_name + if view.additional.get(action) == "ALLOW": + return True + if action == "create" and view.additional.get("create") == "ALLOW": return True diff --git a/core/serializers/utility.py b/core/serializers/utility.py index eae2cf21..8ecd124a 100644 --- a/core/serializers/utility.py +++ b/core/serializers/utility.py @@ -122,7 +122,7 @@ class RecursiveField(Field): class AddOrderProductSerializer(Serializer): product_uuid = CharField(required=True) - attributes = JSONField(required=False, default=dict) + attributes = ListField(required=False, child=DictField(), default=list) class BulkAddOrderProductsSerializer(Serializer): diff --git a/core/viewsets.py b/core/viewsets.py index ffef153a..afe5e17d 100644 --- a/core/viewsets.py +++ b/core/viewsets.py @@ -17,6 +17,7 @@ from drf_spectacular.utils import extend_schema_view from rest_framework import status from rest_framework.decorators import action from rest_framework.exceptions import PermissionDenied +from rest_framework.permissions import AllowAny from rest_framework.renderers import MultiPartRenderer from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet @@ -283,7 +284,7 @@ class CategoryViewSet(EvibesViewSet): action_serializer_classes = { "list": CategorySimpleSerializer, } - additional = {"seo": "ALLOW"} + additional = {"seo_meta": "ALLOW"} def get_queryset(self): qs = super().get_queryset() @@ -291,8 +292,15 @@ class CategoryViewSet(EvibesViewSet): return qs return qs.filter(is_active=True) - @action(detail=True, methods=["get"], url_path="seo") - def seo(self, request, **kwargs): + @action( + detail=True, + methods=["get"], + url_path="meta", + permission_classes=[ + AllowAny, + ], + ) + def seo_meta(self, request, **kwargs): lookup_key = getattr(self, "lookup_url_kwarg", "pk") lookup_val = kwargs.get(lookup_key) @@ -304,13 +312,14 @@ class CategoryViewSet(EvibesViewSet): title = f"{category.name} | {config.PROJECT_NAME}" description = (category.description or "")[:180] canonical = f"https://{config.BASE_DOMAIN}/{settings.LANGUAGE_CODE}/catalog/{category.slug}" + og_image = request.build_absolute_uri(category.image.url) if getattr(category, "image", None) else "" og = { "title": title, "description": description, "type": "website", "url": canonical, - "image": category.image.url if getattr(category, "image", None) else "", + "image": og_image, } tw = {"card": "summary_large_image", "title": title, "description": description} @@ -379,7 +388,7 @@ class BrandViewSet(EvibesViewSet): action_serializer_classes = { "list": BrandSimpleSerializer, } - additional = {"seo": "ALLOW"} + additional = {"seo_meta": "ALLOW"} def get_queryset(self): queryset = Brand.objects.all() @@ -393,8 +402,15 @@ class BrandViewSet(EvibesViewSet): return queryset - @action(detail=True, methods=["get"], url_path="seo") - def seo(self, request, **kwargs): + @action( + detail=True, + methods=["get"], + url_path="meta", + permission_classes=[ + AllowAny, + ], + ) + def seo_meta(self, request, **kwargs): lookup_key = getattr(self, "lookup_url_kwarg", "pk") lookup_val = kwargs.get(lookup_key) brand = get_object_or_404(Brand, slug=str(lookup_val)) @@ -406,9 +422,11 @@ class BrandViewSet(EvibesViewSet): canonical = f"https://{config.BASE_DOMAIN}/{settings.LANGUAGE_CODE}/brand/{brand.slug}" logo_url = ( - brand.big_logo.url + request.build_absolute_uri(brand.big_logo.url) if getattr(brand, "big_logo", None) - else (brand.small_logo.url if getattr(brand, "small_logo", None) else None) + else request.build_absolute_uri(brand.small_logo.url) + if getattr(brand, "small_logo", None) + else "" ) og = { @@ -416,7 +434,7 @@ class BrandViewSet(EvibesViewSet): "description": description, "type": "website", "url": canonical, - "image": logo_url or "", + "image": logo_url, } tw = {"card": "summary_large_image", "title": title, "description": description} @@ -479,7 +497,7 @@ class ProductViewSet(EvibesViewSet): } lookup_field = "lookup_value" lookup_url_kwarg = "lookup_value" - additional = {"seo": "ALLOW"} + additional = {"seo_meta": "ALLOW"} def get_queryset(self): qs = super().get_queryset() @@ -530,30 +548,35 @@ class ProductViewSet(EvibesViewSet): name = "Product" return Response(status=status.HTTP_404_NOT_FOUND, data={"detail": _(f"{name} does not exist: {uuid}")}) - @action(detail=True, methods=["get"], url_path="seo") - def seo(self, request, slug): - p = get_object_or_404(Product.objects.select_related("brand", "category"), slug=slug) + @action( + detail=True, + methods=["get"], + url_path="meta", + permission_classes=[ + AllowAny, + ], + ) + def seo_meta(self, request, **kwargs): + p = self.get_object() images = list(p.images.all()[:6]) rating = {"value": p.rating, "count": p.feedbacks_count} title = f"{p.name} | {config.PROJECT_NAME}" description = (p.description or "")[:180] - canonical = f"https://{config.BASE_DOMAIN}/products/{p.slug}" - + canonical = f"https://{config.BASE_DOMAIN}/{settings.LANGUAGE_CODE}/product/{p.slug}" og = { "title": title, "description": description, "type": "product", "url": canonical, - "image": images[0].image.url if images else "", + "image": request.build_absolute_uri(images[0].image.url) if images else "", } tw = {"card": "summary_large_image", "title": title, "description": description} - crumbs = [] + crumbs = [("Home", f"https://{config.BASE_DOMAIN}/")] if p.category: - crumbs.append(("Home", f"https://{config.BASE_DOMAIN}/")) for c in p.category.get_ancestors(include_self=True): - crumbs.append((c.name, f"https://{config.BASE_DOMAIN}/c/{c.slug}")) - crumbs.append((p.name, canonical)) + crumbs.append((c.name, f"https://{config.BASE_DOMAIN}/{settings.LANGUAGE_CODE}/catalog/{c.slug}")) + crumbs.append((p.name, canonical)) json_ld = [org_schema(), website_schema()] if crumbs: