added endpoints for back office and refactored a little
This commit is contained in:
parent
94f7bda03a
commit
8cf50ff2cd
|
|
@ -290,6 +290,9 @@ class NewsBackOfficeGallerySerializer(serializers.ModelSerializer):
|
||||||
news = news_qs.first()
|
news = news_qs.first()
|
||||||
image = image_qs.first()
|
image = image_qs.first()
|
||||||
|
|
||||||
|
if image in news.gallery.all():
|
||||||
|
raise serializers.ValidationError({'detail': _('Image is already added.')})
|
||||||
|
|
||||||
attrs['news'] = news
|
attrs['news'] = news
|
||||||
attrs['image'] = image
|
attrs['image'] = image
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ from gallery.tasks import delete_image
|
||||||
from news import filters, models, serializers
|
from news import filters, models, serializers
|
||||||
from rating.tasks import add_rating
|
from rating.tasks import add_rating
|
||||||
from utils.permissions import IsCountryAdmin, IsContentPageManager
|
from utils.permissions import IsCountryAdmin, IsContentPageManager
|
||||||
|
from utils.views import CreateDestroyGalleryViewMixin
|
||||||
|
|
||||||
|
|
||||||
class NewsMixinView:
|
class NewsMixinView:
|
||||||
|
|
@ -84,8 +85,7 @@ class NewsBackOfficeLCView(NewsBackOfficeMixinView,
|
||||||
|
|
||||||
|
|
||||||
class NewsBackOfficeGalleryCreateDestroyView(NewsBackOfficeMixinView,
|
class NewsBackOfficeGalleryCreateDestroyView(NewsBackOfficeMixinView,
|
||||||
generics.CreateAPIView,
|
CreateDestroyGalleryViewMixin):
|
||||||
generics.DestroyAPIView):
|
|
||||||
"""Resource for a create gallery for news for back-office users."""
|
"""Resource for a create gallery for news for back-office users."""
|
||||||
serializer_class = serializers.NewsBackOfficeGallerySerializer
|
serializer_class = serializers.NewsBackOfficeGallerySerializer
|
||||||
|
|
||||||
|
|
@ -103,24 +103,6 @@ class NewsBackOfficeGalleryCreateDestroyView(NewsBackOfficeMixinView,
|
||||||
|
|
||||||
return gallery
|
return gallery
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
"""Overridden create method"""
|
|
||||||
super().create(request, *args, **kwargs)
|
|
||||||
return Response(status=status.HTTP_201_CREATED)
|
|
||||||
|
|
||||||
def destroy(self, request, *args, **kwargs):
|
|
||||||
"""Override destroy method."""
|
|
||||||
gallery_obj = self.get_object()
|
|
||||||
if settings.USE_CELERY:
|
|
||||||
on_commit(lambda: delete_image.delay(image_id=gallery_obj.image.id,
|
|
||||||
completely=False))
|
|
||||||
else:
|
|
||||||
on_commit(lambda: delete_image(image_id=gallery_obj.image.id,
|
|
||||||
completely=False))
|
|
||||||
# Delete an instances of NewsGallery model
|
|
||||||
gallery_obj.delete()
|
|
||||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
|
||||||
|
|
||||||
|
|
||||||
class NewsBackOfficeGalleryListView(NewsBackOfficeMixinView, generics.ListAPIView):
|
class NewsBackOfficeGalleryListView(NewsBackOfficeMixinView, generics.ListAPIView):
|
||||||
"""Resource for returning gallery for news for back-office users."""
|
"""Resource for returning gallery for news for back-office users."""
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from product import models
|
|
||||||
from product.serializers import ProductDetailSerializer
|
|
||||||
from gallery.models import Image
|
from gallery.models import Image
|
||||||
|
from product import models
|
||||||
|
from product.serializers import ProductDetailSerializer, ProductTypeBaseSerializer
|
||||||
|
from tag.models import TagCategory
|
||||||
|
|
||||||
|
|
||||||
class ProductBackOfficeGallerySerializer(serializers.ModelSerializer):
|
class ProductBackOfficeGallerySerializer(serializers.ModelSerializer):
|
||||||
|
|
@ -33,12 +34,16 @@ class ProductBackOfficeGallerySerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
if not product_qs.exists():
|
if not product_qs.exists():
|
||||||
raise serializers.ValidationError({'detail': _('Product not found')})
|
raise serializers.ValidationError({'detail': _('Product not found')})
|
||||||
|
|
||||||
if not image_qs.exists():
|
if not image_qs.exists():
|
||||||
raise serializers.ValidationError({'detail': _('Image not found')})
|
raise serializers.ValidationError({'detail': _('Image not found')})
|
||||||
|
|
||||||
product = product_qs.first()
|
product = product_qs.first()
|
||||||
image = image_qs.first()
|
image = image_qs.first()
|
||||||
|
|
||||||
|
if image in product.gallery.all():
|
||||||
|
raise serializers.ValidationError({'detail': _('Image is already added.')})
|
||||||
|
|
||||||
attrs['product'] = product
|
attrs['product'] = product
|
||||||
attrs['image'] = image
|
attrs['image'] = image
|
||||||
|
|
||||||
|
|
@ -46,8 +51,10 @@ class ProductBackOfficeGallerySerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
|
||||||
class ProductBackOfficeDetailSerializer(ProductDetailSerializer):
|
class ProductBackOfficeDetailSerializer(ProductDetailSerializer):
|
||||||
|
"""Product back-office detail serializer."""
|
||||||
|
|
||||||
class Meta(ProductDetailSerializer.Meta):
|
class Meta(ProductDetailSerializer.Meta):
|
||||||
|
"""Meta class."""
|
||||||
fields = ProductDetailSerializer.Meta.fields + [
|
fields = ProductDetailSerializer.Meta.fields + [
|
||||||
'description',
|
'description',
|
||||||
'available',
|
'available',
|
||||||
|
|
@ -68,3 +75,58 @@ class ProductBackOfficeDetailSerializer(ProductDetailSerializer):
|
||||||
'wine_village': {'write_only': True},
|
'wine_village': {'write_only': True},
|
||||||
'state': {'write_only': True},
|
'state': {'write_only': True},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTypeBackOfficeDetailSerializer(ProductTypeBaseSerializer):
|
||||||
|
"""Product type back-office detail serializer."""
|
||||||
|
|
||||||
|
class Meta(ProductTypeBaseSerializer.Meta):
|
||||||
|
"""Meta class."""
|
||||||
|
fields = ProductTypeBaseSerializer.Meta.fields + [
|
||||||
|
'name',
|
||||||
|
'index_name',
|
||||||
|
'use_subtypes',
|
||||||
|
]
|
||||||
|
extra_kwargs = {
|
||||||
|
'name': {'write_only': True},
|
||||||
|
'index_name': {'write_only': True},
|
||||||
|
'use_subtypes': {'write_only': True},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTypeTagCategorySerializer(serializers.ModelSerializer):
|
||||||
|
"""Serializer for attaching tag category to product type."""
|
||||||
|
product_type_id = serializers.PrimaryKeyRelatedField(
|
||||||
|
queryset=models.ProductType.objects.all(),
|
||||||
|
write_only=True)
|
||||||
|
tag_category_id = serializers.PrimaryKeyRelatedField(
|
||||||
|
queryset=TagCategory.objects.all(),
|
||||||
|
write_only=True)
|
||||||
|
|
||||||
|
class Meta(ProductTypeBaseSerializer.Meta):
|
||||||
|
"""Meta class."""
|
||||||
|
fields = ProductTypeBaseSerializer.Meta.fields + [
|
||||||
|
'product_type_id',
|
||||||
|
'tag_category_id',
|
||||||
|
]
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
"""Validation method."""
|
||||||
|
product_type = attrs.pop('product_type_id')
|
||||||
|
tag_category = attrs.get('tag_category_id')
|
||||||
|
|
||||||
|
if tag_category in product_type.tag_categories.all():
|
||||||
|
raise serializers.ValidationError({
|
||||||
|
'detail': _('Tag category is already attached.')})
|
||||||
|
|
||||||
|
attrs['product_type'] = product_type
|
||||||
|
attrs['tag_category'] = tag_category
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
"""Overridden create method."""
|
||||||
|
product_type = validated_data.get('product_type')
|
||||||
|
tag_category = validated_data.get('tag_category')
|
||||||
|
|
||||||
|
product_type.tag_categories.add(tag_category)
|
||||||
|
return product_type
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,8 @@ class ProductSubTypeBaseSerializer(serializers.ModelSerializer):
|
||||||
class ProductTypeBaseSerializer(serializers.ModelSerializer):
|
class ProductTypeBaseSerializer(serializers.ModelSerializer):
|
||||||
"""ProductType base serializer"""
|
"""ProductType base serializer"""
|
||||||
name_translated = TranslatedField()
|
name_translated = TranslatedField()
|
||||||
index_name_display = serializers.CharField(source='get_index_name_display')
|
index_name_display = serializers.CharField(source='get_index_name_display',
|
||||||
|
read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.ProductType
|
model = models.ProductType
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,27 @@
|
||||||
"""Product backoffice url patterns."""
|
"""Product backoffice url patterns."""
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from product.urls.common import urlpatterns as common_urlpatterns
|
|
||||||
from product import views
|
from product import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path('', views.ProductListCreateBackOfficeView.as_view(), name='list-create'),
|
||||||
path('<int:pk>/', views.ProductDetailBackOfficeView.as_view(), name='rud'),
|
path('<int:pk>/', views.ProductDetailBackOfficeView.as_view(), name='rud'),
|
||||||
path('<int:pk>/gallery/', views.ProductBackOfficeGalleryListView.as_view(),
|
path('<int:pk>/gallery/', views.ProductBackOfficeGalleryListView.as_view(),
|
||||||
name='gallery-list'),
|
name='gallery-list'),
|
||||||
path('<int:pk>/gallery/<int:image_id>/', views.ProductBackOfficeGalleryCreateDestroyView.as_view(),
|
path('<int:pk>/gallery/<int:image_id>/', views.ProductBackOfficeGalleryCreateDestroyView.as_view(),
|
||||||
name='gallery-create-destroy'),
|
name='gallery-create-destroy'),
|
||||||
]
|
# product types
|
||||||
|
path('types/', views.ProductTypeListCreateBackOfficeView.as_view(), name='type-list-create'),
|
||||||
|
path('types/<int:pk>/', views.ProductTypeRUDBackOfficeView.as_view(),
|
||||||
|
name='type-retrieve-update-destroy'),
|
||||||
|
path('types/attach-tag-category/', views.ProductTypeTagCategoryCreateBackOfficeView.as_view(),
|
||||||
|
name='type-tag-category-create'),
|
||||||
|
# product sub types
|
||||||
|
# path('subtypes/', views.ProductSubTypeListCreateBackOfficeView.as_view(),
|
||||||
|
# name='subtype-list-create'),
|
||||||
|
# path('subtypes/<int:pk>/', views.ProductSubTypeRUDBackOfficeView.as_view(),
|
||||||
|
# name='subtype-retrieve-update-destroy'),
|
||||||
|
# path('subtypes/attach-tag-category/', views.ProductSubTypeTagCategoryCreateBackOfficeView.as_view(),
|
||||||
|
# name='subtype-tag-category-create'),
|
||||||
|
|
||||||
urlpatterns.extend(common_urlpatterns)
|
]
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.transaction import on_commit
|
from django.db.transaction import on_commit
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from rest_framework import generics, status, permissions
|
from rest_framework import generics, status, permissions, views
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from gallery.tasks import delete_image
|
from gallery.tasks import delete_image
|
||||||
from product import serializers, models
|
from product import serializers, models
|
||||||
|
from utils.views import CreateDestroyGalleryViewMixin
|
||||||
|
|
||||||
|
|
||||||
class ProductBackOfficeMixinView:
|
class ProductBackOfficeMixinView:
|
||||||
|
|
@ -17,9 +18,34 @@ class ProductBackOfficeMixinView:
|
||||||
.order_by('-created', )
|
.order_by('-created', )
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTypeBackOfficeMixinView:
|
||||||
|
"""Product type back-office mixin view."""
|
||||||
|
|
||||||
|
permission_classes = (permissions.IsAuthenticated,)
|
||||||
|
queryset = models.ProductType.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
class ProductSubTypeBackOfficeMixinView:
|
||||||
|
"""Product sub type back-office mixin view."""
|
||||||
|
|
||||||
|
permission_classes = (permissions.IsAuthenticated,)
|
||||||
|
queryset = models.ProductSubType.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
class BackOfficeListCreateMixin(views.APIView):
|
||||||
|
"""Back-office list-create mixin view."""
|
||||||
|
|
||||||
|
def check_permissions(self, request):
|
||||||
|
"""
|
||||||
|
Check if the request should be permitted.
|
||||||
|
Raises an appropriate exception if the request is not permitted.
|
||||||
|
"""
|
||||||
|
if self.request.method != 'GET':
|
||||||
|
super().check_permissions(request)
|
||||||
|
|
||||||
|
|
||||||
class ProductBackOfficeGalleryCreateDestroyView(ProductBackOfficeMixinView,
|
class ProductBackOfficeGalleryCreateDestroyView(ProductBackOfficeMixinView,
|
||||||
generics.CreateAPIView,
|
CreateDestroyGalleryViewMixin):
|
||||||
generics.DestroyAPIView):
|
|
||||||
"""Resource for a create gallery for product for back-office users."""
|
"""Resource for a create gallery for product for back-office users."""
|
||||||
serializer_class = serializers.ProductBackOfficeGallerySerializer
|
serializer_class = serializers.ProductBackOfficeGallerySerializer
|
||||||
|
|
||||||
|
|
@ -37,24 +63,6 @@ class ProductBackOfficeGalleryCreateDestroyView(ProductBackOfficeMixinView,
|
||||||
|
|
||||||
return gallery
|
return gallery
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
"""Overridden create method"""
|
|
||||||
super().create(request, *args, **kwargs)
|
|
||||||
return Response(status=status.HTTP_201_CREATED)
|
|
||||||
|
|
||||||
def destroy(self, request, *args, **kwargs):
|
|
||||||
"""Override destroy method."""
|
|
||||||
gallery_obj = self.get_object()
|
|
||||||
if settings.USE_CELERY:
|
|
||||||
on_commit(lambda: delete_image.delay(image_id=gallery_obj.image.id,
|
|
||||||
completely=False))
|
|
||||||
else:
|
|
||||||
on_commit(lambda: delete_image(image_id=gallery_obj.image.id,
|
|
||||||
completely=False))
|
|
||||||
# Delete an instances of ProductGallery model
|
|
||||||
gallery_obj.delete()
|
|
||||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
|
||||||
|
|
||||||
|
|
||||||
class ProductBackOfficeGalleryListView(ProductBackOfficeMixinView, generics.ListAPIView):
|
class ProductBackOfficeGalleryListView(ProductBackOfficeMixinView, generics.ListAPIView):
|
||||||
"""Resource for returning gallery for product for back-office users."""
|
"""Resource for returning gallery for product for back-office users."""
|
||||||
|
|
@ -78,3 +86,32 @@ class ProductBackOfficeGalleryListView(ProductBackOfficeMixinView, generics.List
|
||||||
class ProductDetailBackOfficeView(ProductBackOfficeMixinView, generics.RetrieveUpdateDestroyAPIView):
|
class ProductDetailBackOfficeView(ProductBackOfficeMixinView, generics.RetrieveUpdateDestroyAPIView):
|
||||||
"""Product back-office R/U/D view."""
|
"""Product back-office R/U/D view."""
|
||||||
serializer_class = serializers.ProductBackOfficeDetailSerializer
|
serializer_class = serializers.ProductBackOfficeDetailSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class ProductListCreateBackOfficeView(BackOfficeListCreateMixin, ProductBackOfficeMixinView,
|
||||||
|
generics.ListCreateAPIView):
|
||||||
|
"""Product back-office list-create view."""
|
||||||
|
serializer_class = serializers.ProductBackOfficeDetailSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTypeListCreateBackOfficeView(BackOfficeListCreateMixin, ProductTypeBackOfficeMixinView,
|
||||||
|
generics.ListCreateAPIView):
|
||||||
|
"""Product type back-office list-create view."""
|
||||||
|
serializer_class = serializers.ProductTypeBackOfficeDetailSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTypeRUDBackOfficeView(BackOfficeListCreateMixin, ProductTypeBackOfficeMixinView,
|
||||||
|
generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
"""Product type back-office retrieve-update-destroy view."""
|
||||||
|
serializer_class = serializers.ProductTypeBackOfficeDetailSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTypeTagCategoryCreateBackOfficeView(ProductTypeBackOfficeMixinView,
|
||||||
|
generics.CreateAPIView):
|
||||||
|
"""View for attaching tag category to product type."""
|
||||||
|
serializer_class = serializers.ProductTypeTagCategorySerializer
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
super().create(request, *args, **kwargs)
|
||||||
|
return Response(status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.db.transaction import on_commit
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
|
from gallery.tasks import delete_image
|
||||||
|
|
||||||
|
|
||||||
# JWT
|
# JWT
|
||||||
# Login base view mixins
|
# Login base view mixins
|
||||||
|
|
@ -95,3 +98,26 @@ class JWTGenericViewMixin(generics.GenericAPIView):
|
||||||
http_only=self.REFRESH_TOKEN_HTTP_ONLY,
|
http_only=self.REFRESH_TOKEN_HTTP_ONLY,
|
||||||
secure=self.REFRESH_TOKEN_SECURE,
|
secure=self.REFRESH_TOKEN_SECURE,
|
||||||
max_age=_cookies.get('max_age'))]
|
max_age=_cookies.get('max_age'))]
|
||||||
|
|
||||||
|
|
||||||
|
class CreateDestroyGalleryViewMixin(generics.CreateAPIView,
|
||||||
|
generics.DestroyAPIView):
|
||||||
|
"""Mixin for creating and destroying entity linked with gallery."""
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
"""Overridden create method"""
|
||||||
|
super().create(request, *args, **kwargs)
|
||||||
|
return Response(status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
def destroy(self, request, *args, **kwargs):
|
||||||
|
"""Override destroy method."""
|
||||||
|
gallery_obj = self.get_object()
|
||||||
|
if settings.USE_CELERY:
|
||||||
|
on_commit(lambda: delete_image.delay(image_id=gallery_obj.image.id,
|
||||||
|
completely=False))
|
||||||
|
else:
|
||||||
|
on_commit(lambda: delete_image(image_id=gallery_obj.image.id,
|
||||||
|
completely=False))
|
||||||
|
# Delete an instances of Gallery model
|
||||||
|
gallery_obj.delete()
|
||||||
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user