Merge remote-tracking branch 'origin/develop' into es_product
This commit is contained in:
commit
bbb72dabbe
|
|
@ -10,4 +10,5 @@ urlpatterns = [
|
|||
path('user-role/', views.UserRoleLstView.as_view(), name='user-role-list-create'),
|
||||
path('user/', views.UserLstView.as_view(), name='user-create-list'),
|
||||
path('user/<int:id>/', views.UserRUDView.as_view(), name='user-rud'),
|
||||
path('user/<int:id>/csv', views.get_user_csv, name='user-csv'),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import generics, permissions
|
||||
from rest_framework.filters import OrderingFilter
|
||||
import csv
|
||||
from django.http import HttpResponse, HttpResponseNotFound
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
from account import models
|
||||
from account.models import User
|
||||
|
|
@ -46,3 +49,69 @@ class UserRUDView(generics.RetrieveUpdateDestroyAPIView):
|
|||
serializer_class = serializers.BackDetailUserSerializer
|
||||
permission_classes = (permissions.IsAdminUser,)
|
||||
lookup_field = 'id'
|
||||
|
||||
|
||||
def get_user_csv(request, id):
|
||||
# fields = ["id", "uuid", "nickname", "locale", "country_code", "city", "role", "consent_purpose", "consent_at",
|
||||
# "last_seen_at", "created_at", "updated_at", "email", "is_admin", "ezuser_id", "ez_user_id",
|
||||
# "encrypted_password", "reset_password_token", "reset_password_sent_at", "remember_created_at",
|
||||
# "sign_in_count", "current_sign_in_at", "last_sign_in_at", "current_sign_in_ip", "last_sign_in_ip",
|
||||
# "confirmation_token", "confirmed_at", "confirmation_sent_at", "unconfirmed_email", "webpush_subscription"]
|
||||
|
||||
# uuid == id
|
||||
#
|
||||
# Не найдены:
|
||||
# consent_purpose
|
||||
# consent_at
|
||||
# ezuser_id
|
||||
# ez_user_id
|
||||
# remember_created_at
|
||||
# sign_in_count
|
||||
# current_sign_in_at
|
||||
# current_sign_in_ip
|
||||
# last_sign_in_ip
|
||||
# confirmed_at
|
||||
# confirmation_sent_at
|
||||
# webpush_subscription
|
||||
#
|
||||
# country_code не получить - клиент не привязан к стране
|
||||
|
||||
try:
|
||||
user = User.objects.get(id=id)
|
||||
except User.DoesNotExist:
|
||||
return HttpResponseNotFound("User not found")
|
||||
|
||||
try:
|
||||
roles = " ".join([role for role in user.roles])
|
||||
except:
|
||||
roles = ""
|
||||
|
||||
token, _ = Token.objects.get_or_create(user=user)
|
||||
|
||||
fields = {
|
||||
"id": user.id,
|
||||
"uuid": user.id,
|
||||
"username": getattr(user, "username", ""),
|
||||
"locale": getattr(user, "locale", ""),
|
||||
"city": getattr(user, "city", ""),
|
||||
"role": roles,
|
||||
"created_at": getattr(user, "date_joined", ""),
|
||||
"updated_at": user.last_login,
|
||||
"email": user.email,
|
||||
"is_admin": user.is_superuser,
|
||||
"encrypted_password": user.password,
|
||||
"reset_password_token": token.key,
|
||||
"reset_password_sent_at": token.created, # TODO: не уверен в назначении поля, лучше проверить
|
||||
"last_sign_in_at": user.last_login, # Повтор?
|
||||
"confirmation_token": user.confirm_email_token,
|
||||
"unconfirmed_email": 1 if user.unconfirmed_email else 0
|
||||
}
|
||||
|
||||
response = HttpResponse(content_type='text/csv')
|
||||
response['Content-Disposition'] = f'attachment; filename="{user.email}.csv"'
|
||||
|
||||
writer = csv.writer(response)
|
||||
writer.writerow(fields.keys())
|
||||
writer.writerow(fields.values())
|
||||
|
||||
return response
|
||||
|
|
|
|||
|
|
@ -14,3 +14,8 @@ class PageInline(admin.TabularInline):
|
|||
class AdvertisementModelAdmin(admin.ModelAdmin):
|
||||
"""Admin model for model Advertisement"""
|
||||
inlines = (PageInline, )
|
||||
list_display = ('id', '__str__', 'block_level',
|
||||
'start', 'end', 'page_type')
|
||||
list_filter = ('url', 'block_level', 'start', 'end', 'page_type',
|
||||
'pages__source')
|
||||
date_hierarchy = 'created'
|
||||
|
|
|
|||
|
|
@ -71,11 +71,11 @@ class Advertisement(ProjectBaseMixin):
|
|||
return super().delete(using, keep_parents)
|
||||
|
||||
@property
|
||||
def mobile_page(self):
|
||||
def mobile_pages(self):
|
||||
"""Return mobile page"""
|
||||
return self.pages.by_platform(Page.MOBILE).first()
|
||||
return self.pages.by_platform(Page.MOBILE)
|
||||
|
||||
@property
|
||||
def web_page(self):
|
||||
def web_pages(self):
|
||||
"""Return web page"""
|
||||
return self.pages.by_platform(Page.WEB).first()
|
||||
return self.pages.by_platform(Page.WEB)
|
||||
|
|
|
|||
|
|
@ -1,26 +1,14 @@
|
|||
"""Serializers for back office app advertisements"""
|
||||
from main.serializers import PageBaseSerializer
|
||||
from advertisement.serializers import AdvertisementBaseSerializer
|
||||
from main.serializers import PageExtendedSerializer
|
||||
|
||||
|
||||
class AdvertisementPageBaseSerializer(PageBaseSerializer):
|
||||
"""Base serializer for linking page w/ advertisement."""
|
||||
class AdvertisementDetailSerializer(AdvertisementBaseSerializer):
|
||||
"""Advertisement serializer for back office."""
|
||||
pages = PageExtendedSerializer(many=True, read_only=True)
|
||||
|
||||
class Meta(PageBaseSerializer.Meta):
|
||||
class Meta(AdvertisementBaseSerializer.Meta):
|
||||
"""Meta class."""
|
||||
|
||||
PageBaseSerializer.Meta.extra_kwargs.update({
|
||||
'advertisement': {'write_only': True},
|
||||
'image_url': {'required': True},
|
||||
'width': {'required': True},
|
||||
'height': {'required': True},
|
||||
})
|
||||
|
||||
|
||||
class AdvertisementPageListCreateSerializer(AdvertisementPageBaseSerializer):
|
||||
"""Serializer for linking page w/ advertisement."""
|
||||
|
||||
def create(self, validated_data):
|
||||
"""Overridden create method."""
|
||||
|
||||
validated_data['advertisement'] = self.context.get('view').get_object()
|
||||
return super().create(validated_data)
|
||||
fields = AdvertisementBaseSerializer.Meta.fields + [
|
||||
'pages',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from advertisement import models
|
||||
from translation.serializers import LanguageSerializer
|
||||
from main.serializers import SiteShortSerializer, PageBaseSerializer
|
||||
from translation.models import Language
|
||||
from main.models import SiteSettings
|
||||
from main.serializers import PageTypeBaseSerializer
|
||||
from translation.models import Language
|
||||
|
||||
|
||||
class AdvertisementBaseSerializer(serializers.ModelSerializer):
|
||||
"""Base serializer for model Advertisement."""
|
||||
|
||||
page_type_detail = PageTypeBaseSerializer(read_only=True,
|
||||
source='page_type')
|
||||
target_languages = serializers.PrimaryKeyRelatedField(
|
||||
queryset=Language.objects.all(),
|
||||
many=True,
|
||||
|
|
@ -34,16 +34,17 @@ class AdvertisementBaseSerializer(serializers.ModelSerializer):
|
|||
'target_sites',
|
||||
'start',
|
||||
'end',
|
||||
'page_type',
|
||||
'page_type_detail',
|
||||
]
|
||||
extra_kwargs = {
|
||||
'page_type': {'required': True, 'write_only': True}
|
||||
}
|
||||
|
||||
|
||||
class AdvertisementPageTypeCommonListSerializer(AdvertisementBaseSerializer):
|
||||
"""Serializer for AdvertisementPageTypeCommonView."""
|
||||
|
||||
page = PageBaseSerializer(source='common_page', read_only=True)
|
||||
|
||||
class AdvertisementSerializer(AdvertisementBaseSerializer):
|
||||
"""Serializer for model Advertisement."""
|
||||
class Meta(AdvertisementBaseSerializer.Meta):
|
||||
"""Meta class."""
|
||||
fields = AdvertisementBaseSerializer.Meta.fields + [
|
||||
'page',
|
||||
]
|
||||
fields = AdvertisementBaseSerializer.Meta.fields.copy()
|
||||
fields.pop(fields.index('page_type_detail'))
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
"""Serializers for mobile app advertisements"""
|
||||
from advertisement.serializers import AdvertisementBaseSerializer
|
||||
from advertisement.serializers import AdvertisementSerializer
|
||||
from main.serializers import PageBaseSerializer
|
||||
|
||||
|
||||
class AdvertisementPageTypeMobileListSerializer(AdvertisementBaseSerializer):
|
||||
class AdvertisementPageTypeMobileListSerializer(AdvertisementSerializer):
|
||||
"""Serializer for AdvertisementPageTypeMobileView."""
|
||||
|
||||
page = PageBaseSerializer(source='mobile_page', read_only=True)
|
||||
pages = PageBaseSerializer(many=True, source='mobile_pages', read_only=True)
|
||||
|
||||
class Meta(AdvertisementBaseSerializer.Meta):
|
||||
class Meta(AdvertisementSerializer.Meta):
|
||||
"""Meta class."""
|
||||
fields = AdvertisementBaseSerializer.Meta.fields + [
|
||||
'page',
|
||||
fields = AdvertisementSerializer.Meta.fields + [
|
||||
'pages',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
"""Serializers for web app advertisements"""
|
||||
from advertisement.serializers import AdvertisementBaseSerializer
|
||||
from advertisement.serializers import AdvertisementSerializer
|
||||
from main.serializers import PageBaseSerializer
|
||||
|
||||
|
||||
class AdvertisementPageTypeWebListSerializer(AdvertisementBaseSerializer):
|
||||
class AdvertisementPageTypeWebListSerializer(AdvertisementSerializer):
|
||||
"""Serializer for AdvertisementPageTypeWebView."""
|
||||
|
||||
page = PageBaseSerializer(source='web_page', read_only=True)
|
||||
pages = PageBaseSerializer(many=True, source='web_pages', read_only=True)
|
||||
|
||||
class Meta(AdvertisementBaseSerializer.Meta):
|
||||
class Meta(AdvertisementSerializer.Meta):
|
||||
"""Meta class."""
|
||||
fields = AdvertisementBaseSerializer.Meta.fields + [
|
||||
'page',
|
||||
fields = AdvertisementSerializer.Meta.fields + [
|
||||
'pages',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ app_name = 'advertisements'
|
|||
urlpatterns = [
|
||||
path('', views.AdvertisementListCreateView.as_view(), name='list-create'),
|
||||
path('<int:pk>/', views.AdvertisementRUDView.as_view(), name='rud'),
|
||||
path('<int:pk>/pages/', views.AdvertisementPageListCreateView.as_view(),
|
||||
name='page-list-create'),
|
||||
path('<int:ad_pk>/pages/<int:page_pk>/', views.AdvertisementPageRUDView.as_view(),
|
||||
name='page-rud')
|
||||
path('<int:pk>/pages/', views.AdvertisementPageCreateView.as_view(),
|
||||
name='ad-page-create'),
|
||||
path('<int:ad_pk>/pages/<int:page_pk>/', views.AdvertisementPageUDView.as_view(),
|
||||
name='ad-page-update-destroy')
|
||||
]
|
||||
|
||||
urlpatterns += common_urlpatterns
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
"""Back office views for app advertisement"""
|
||||
from rest_framework import generics
|
||||
from rest_framework import generics, status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import permissions
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from main.serializers import PageExtendedSerializer
|
||||
from advertisement.models import Advertisement
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
from advertisement.serializers import (AdvertisementBaseSerializer,
|
||||
AdvertisementPageBaseSerializer,
|
||||
AdvertisementPageListCreateSerializer)
|
||||
AdvertisementDetailSerializer)
|
||||
|
||||
|
||||
class AdvertisementBackOfficeViewMixin(generics.GenericAPIView):
|
||||
"""Base back office advertisement view."""
|
||||
|
||||
pagination_class = None
|
||||
permission_classes = (permissions.IsAuthenticated, )
|
||||
|
||||
def get_queryset(self):
|
||||
|
|
@ -31,14 +31,14 @@ class AdvertisementRUDView(AdvertisementBackOfficeViewMixin,
|
|||
generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Retrieve|Update|Destroy advertisement page view."""
|
||||
|
||||
serializer_class = AdvertisementBaseSerializer
|
||||
serializer_class = AdvertisementDetailSerializer
|
||||
|
||||
|
||||
class AdvertisementPageListCreateView(AdvertisementBackOfficeViewMixin,
|
||||
generics.ListCreateAPIView):
|
||||
"""Retrieve|Update|Destroy advertisement page view."""
|
||||
class AdvertisementPageCreateView(AdvertisementBackOfficeViewMixin,
|
||||
generics.CreateAPIView):
|
||||
"""Create advertisement page view."""
|
||||
|
||||
serializer_class = AdvertisementPageListCreateSerializer
|
||||
serializer_class = PageExtendedSerializer
|
||||
|
||||
def get_object(self):
|
||||
"""Returns the object the view is displaying."""
|
||||
|
|
@ -56,12 +56,19 @@ class AdvertisementPageListCreateView(AdvertisementBackOfficeViewMixin,
|
|||
"""Overridden get_queryset method."""
|
||||
return self.get_object().pages.all()
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
"""Overridden create method."""
|
||||
request.data.update({'advertisement': self.get_object().pk})
|
||||
super().create(request, *args, **kwargs)
|
||||
return Response(status=status.HTTP_200_OK)
|
||||
|
||||
class AdvertisementPageRUDView(AdvertisementBackOfficeViewMixin,
|
||||
generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Create|Retrieve|Update|Destroy advertisement page view."""
|
||||
|
||||
serializer_class = AdvertisementPageBaseSerializer
|
||||
class AdvertisementPageUDView(AdvertisementBackOfficeViewMixin,
|
||||
generics.UpdateAPIView,
|
||||
generics.DestroyAPIView):
|
||||
"""Update|Destroy advertisement page view."""
|
||||
|
||||
serializer_class = PageExtendedSerializer
|
||||
|
||||
def get_object(self):
|
||||
"""Returns the object the view is displaying."""
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ from rest_framework import generics
|
|||
from rest_framework import permissions
|
||||
|
||||
from advertisement.models import Advertisement
|
||||
from advertisement.serializers import AdvertisementBaseSerializer, \
|
||||
AdvertisementPageTypeCommonListSerializer
|
||||
from advertisement.serializers import AdvertisementBaseSerializer
|
||||
|
||||
|
||||
class AdvertisementBaseView(generics.GenericAPIView):
|
||||
|
|
@ -16,8 +15,7 @@ class AdvertisementBaseView(generics.GenericAPIView):
|
|||
|
||||
def get_queryset(self):
|
||||
"""Overridden get queryset method."""
|
||||
return Advertisement.objects.with_base_related() \
|
||||
.by_locale(self.request.locale)
|
||||
return Advertisement.objects.with_base_related()
|
||||
|
||||
|
||||
class AdvertisementPageTypeListView(AdvertisementBaseView, generics.ListAPIView):
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
from django.conf import settings
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
from django.core.files.base import ContentFile
|
||||
from rest_framework import serializers
|
||||
from sorl.thumbnail.parsers import parse_crop
|
||||
from sorl.thumbnail.parsers import ThumbnailParseError
|
||||
from sorl.thumbnail import get_thumbnail
|
||||
from sorl.thumbnail.parsers import parse_crop, ThumbnailParseError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from . import models
|
||||
|
|
@ -88,15 +89,23 @@ class CropImageSerializer(ImageSerializer):
|
|||
quality = validated_data.pop('quality')
|
||||
crop = validated_data.pop('crop')
|
||||
|
||||
crop_params = {
|
||||
'geometry': f'{width}x{height}',
|
||||
'quality': quality,
|
||||
'crop': crop,
|
||||
}
|
||||
cropped_image = self._image.get_cropped_image(**crop_params)
|
||||
image = self._image
|
||||
image.pk = None
|
||||
crop_params['geometry_string'] = crop_params.pop('geometry')
|
||||
resized = get_thumbnail(self._image.image, **crop_params)
|
||||
image.image.save(resized.name, ContentFile(resized.read()), True)
|
||||
image.save()
|
||||
|
||||
if image and width and height:
|
||||
setattr(image,
|
||||
'cropped_image',
|
||||
image.get_cropped_image(
|
||||
geometry=f'{width}x{height}',
|
||||
quality=quality,
|
||||
crop=crop))
|
||||
cropped_image)
|
||||
return image
|
||||
|
||||
@property
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ urlpatterns = [
|
|||
path('addresses/<int:pk>/', views.AddressRUDView.as_view(), name='address-RUD'),
|
||||
|
||||
path('cities/', views.CityListCreateView.as_view(), name='city-list-create'),
|
||||
path('cities/all/', views.CityListSearchView.as_view(), name='city-list-create'),
|
||||
path('cities/<int:pk>/', views.CityRUDView.as_view(), name='city-retrieve'),
|
||||
path('cities/<int:pk>/gallery/', views.CityGalleryListView.as_view(),
|
||||
name='gallery-list'),
|
||||
|
|
|
|||
|
|
@ -37,6 +37,15 @@ class CityListCreateView(common.CityViewMixin, generics.ListCreateAPIView):
|
|||
filter_class = filters.CityBackFilter
|
||||
|
||||
|
||||
class CityListSearchView(common.CityViewMixin, generics.ListCreateAPIView):
|
||||
"""Create view for model City."""
|
||||
serializer_class = serializers.CitySerializer
|
||||
permission_classes = [IsAuthenticatedOrReadOnly|IsCountryAdmin]
|
||||
queryset = models.City.objects.all()
|
||||
filter_class = filters.CityBackFilter
|
||||
pagination_class = None
|
||||
|
||||
|
||||
class CityRUDView(common.CityViewMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
"""RUD view for model City."""
|
||||
serializer_class = serializers.CitySerializer
|
||||
|
|
|
|||
|
|
@ -51,3 +51,6 @@ class PageTypeAdmin(admin.ModelAdmin):
|
|||
@admin.register(models.Page)
|
||||
class PageAdmin(admin.ModelAdmin):
|
||||
"""Page admin."""
|
||||
list_display = ('id', '__str__', 'advertisement')
|
||||
list_filter = ('advertisement__url', 'source')
|
||||
date_hierarchy = 'created'
|
||||
|
|
|
|||
18
apps/main/migrations/0041_auto_20191211_0631.py
Normal file
18
apps/main/migrations/0041_auto_20191211_0631.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-11 06:31
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('advertisement', '0008_auto_20191116_1135'),
|
||||
('main', '0040_footer'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='page',
|
||||
unique_together={('advertisement', 'source')},
|
||||
),
|
||||
]
|
||||
|
|
@ -305,7 +305,7 @@ class PageQuerySet(models.QuerySet):
|
|||
|
||||
def by_platform(self, platform: int):
|
||||
"""Filter by platform."""
|
||||
return self.filter(source=platform)
|
||||
return self.filter(source__in=[Page.ALL, platform])
|
||||
|
||||
|
||||
class Page(URLImageMixin, PlatformMixin, ProjectBaseMixin):
|
||||
|
|
@ -325,6 +325,7 @@ class Page(URLImageMixin, PlatformMixin, ProjectBaseMixin):
|
|||
"""Meta class."""
|
||||
verbose_name = _('page')
|
||||
verbose_name_plural = _('pages')
|
||||
unique_together = ('advertisement', 'source')
|
||||
|
||||
def __str__(self):
|
||||
"""Overridden dunder method."""
|
||||
|
|
|
|||
|
|
@ -152,8 +152,6 @@ class SiteShortSerializer(serializers.ModelSerializer):
|
|||
]
|
||||
|
||||
|
||||
|
||||
|
||||
class AwardBaseSerializer(serializers.ModelSerializer):
|
||||
"""Award base serializer."""
|
||||
|
||||
|
|
@ -234,10 +232,26 @@ class PageBaseSerializer(serializers.ModelSerializer):
|
|||
'advertisement',
|
||||
]
|
||||
extra_kwargs = {
|
||||
'establishment': {'write_only': True}
|
||||
'advertisement': {'write_only': True},
|
||||
'image_url': {'required': True},
|
||||
'width': {'required': True},
|
||||
'height': {'required': True},
|
||||
}
|
||||
|
||||
|
||||
class PageExtendedSerializer(PageBaseSerializer):
|
||||
"""Extended serializer for model Page."""
|
||||
source_display = serializers.CharField(read_only=True,
|
||||
source='get_source_display')
|
||||
|
||||
class Meta(PageBaseSerializer.Meta):
|
||||
"""Meta class."""
|
||||
fields = PageBaseSerializer.Meta.fields + [
|
||||
'source',
|
||||
'source_display',
|
||||
]
|
||||
|
||||
|
||||
class PageTypeBaseSerializer(serializers.ModelSerializer):
|
||||
"""Serializer fro model PageType."""
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ urlpatterns = [
|
|||
name='site-feature-rud'),
|
||||
path('footer/', views.FooterBackView.as_view(), name='footer-list-create'),
|
||||
path('footer/<int:pk>/', views.FooterRUDBackView.as_view(), name='footer-rud'),
|
||||
path('page-types/', views.PageTypeListCreateView.as_view(),
|
||||
name='page-types-list-create')
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from rest_framework import generics, permissions
|
|||
|
||||
from main import serializers
|
||||
from main.filters import AwardFilter
|
||||
from main.models import Award, Footer
|
||||
from main.models import Award, Footer, PageType
|
||||
from main.views import SiteSettingsView, SiteListView
|
||||
|
||||
|
||||
|
|
@ -81,3 +81,11 @@ class FooterRUDBackView(generics.RetrieveUpdateDestroyAPIView):
|
|||
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
|
||||
serializer_class = serializers.FooterBackSerializer
|
||||
queryset = Footer.objects.all()
|
||||
|
||||
|
||||
class PageTypeListCreateView(generics.ListCreateAPIView):
|
||||
"""PageType back office view."""
|
||||
permission_classes = (permissions.IsAuthenticatedOrReadOnly, )
|
||||
pagination_class = None
|
||||
serializer_class = serializers.PageTypeBaseSerializer
|
||||
queryset = PageType.objects.all()
|
||||
|
|
|
|||
|
|
@ -70,9 +70,6 @@ class CarouselListView(generics.ListAPIView):
|
|||
|
||||
def get_queryset(self):
|
||||
country_code = self.request.country_code
|
||||
if hasattr(settings, 'CAROUSEL_ITEMS') and country_code in settings.INTERNATIONAL_COUNTRY_CODES:
|
||||
qs = models.Carousel.objects.filter(id__in=settings.CAROUSEL_ITEMS)
|
||||
return qs
|
||||
qs = models.Carousel.objects.is_parsed().active()
|
||||
if country_code:
|
||||
qs = qs.by_country_code(country_code)
|
||||
|
|
|
|||
|
|
@ -177,13 +177,23 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer):
|
|||
'backoffice_title': {'allow_null': False},
|
||||
}
|
||||
|
||||
def validate(self, attrs):
|
||||
slugs = attrs.get('slugs', {})
|
||||
if models.News.objects.filter(
|
||||
slugs__values__contains=list(slugs.values())
|
||||
).exclude(id=attrs.get('id', 0)).exists():
|
||||
raise serializers.ValidationError({'slugs': _('News with this slug already exists.')})
|
||||
return attrs
|
||||
def create(self, validated_data):
|
||||
slugs = validated_data.get('slugs')
|
||||
if slugs:
|
||||
if models.News.objects.filter(
|
||||
slugs__values__contains=list(slugs.values())
|
||||
).exists():
|
||||
raise serializers.ValidationError({'slugs': _('News with this slug already exists.')})
|
||||
return super().create(validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
slugs = validated_data.get('slugs')
|
||||
if slugs:
|
||||
if models.News.objects.filter(
|
||||
slugs__values__contains=list(slugs.values())
|
||||
).exclude(pk=instance.pk).exists():
|
||||
raise serializers.ValidationError({'slugs': _('News with this slug already exists.')})
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
|
||||
class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer,
|
||||
|
|
@ -233,6 +243,15 @@ class NewsBackOfficeGallerySerializer(serializers.ModelSerializer):
|
|||
"""Get url kwargs from request."""
|
||||
return self.context.get('request').parser_context.get('kwargs')
|
||||
|
||||
def create(self, validated_data):
|
||||
news_pk = self.get_request_kwargs().get('pk')
|
||||
image_id = self.get_request_kwargs().get('image_id')
|
||||
news_gallery_model = models.NewsGallery.objects.filter(image_id=image_id, news_id=news_pk).first()
|
||||
if news_gallery_model:
|
||||
news_gallery_model.update(**validated_data)
|
||||
return news_gallery_model
|
||||
return super().create(validated_data)
|
||||
|
||||
def validate(self, attrs):
|
||||
"""Override validate method."""
|
||||
news_pk = self.get_request_kwargs().get('pk')
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
from rest_framework import serializers
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
|
||||
from establishment.models import (Establishment, EstablishmentType)
|
||||
from news.models import News, NewsType
|
||||
from establishment.models import Establishment
|
||||
from establishment.models import EstablishmentType
|
||||
from news.models import News
|
||||
from news.models import NewsType
|
||||
from tag import models
|
||||
from utils.exceptions import (ObjectAlreadyAdded, BindingObjectNotFound,
|
||||
RemovedBindingObjectNotFound)
|
||||
from utils.exceptions import BindingObjectNotFound
|
||||
from utils.exceptions import ObjectAlreadyAdded
|
||||
from utils.exceptions import RemovedBindingObjectNotFound
|
||||
from utils.serializers import TranslatedField
|
||||
|
||||
|
||||
|
|
@ -95,6 +98,72 @@ class TagCategoryBaseSerializer(serializers.ModelSerializer):
|
|||
return TagBaseSerializer(instance=tags, many=True, read_only=True).data
|
||||
|
||||
|
||||
class FiltersTagCategoryBaseSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for model TagCategory."""
|
||||
|
||||
label_translated = TranslatedField()
|
||||
filters = SerializerMethodField()
|
||||
param_name = SerializerMethodField()
|
||||
type = SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
model = models.TagCategory
|
||||
fields = (
|
||||
'id',
|
||||
'label_translated',
|
||||
'index_name',
|
||||
'param_name',
|
||||
'type',
|
||||
'filters',
|
||||
)
|
||||
|
||||
def get_type(self, obj):
|
||||
return obj in ['open_now', ]
|
||||
|
||||
def get_param_name(self, obj):
|
||||
if obj == 'service':
|
||||
return 'tags_id__in'
|
||||
|
||||
elif obj == 'pop':
|
||||
return 'tags_id__in'
|
||||
|
||||
elif obj == 'open_now':
|
||||
return 'open_now'
|
||||
|
||||
elif obj == 'wine_region':
|
||||
return 'wine_region_id__in'
|
||||
|
||||
return '%s__in' % obj.index_name
|
||||
|
||||
def get_fields(self, *args, **kwargs):
|
||||
fields = super(FiltersTagCategoryBaseSerializer, self).get_fields()
|
||||
|
||||
if self.get_type(self):
|
||||
fields.pop('filters', None)
|
||||
else:
|
||||
fields.pop('type', None)
|
||||
|
||||
return fields
|
||||
|
||||
def get_filters(self, obj):
|
||||
query_params = dict(self.context['request'].query_params)
|
||||
|
||||
params = {}
|
||||
if 'establishment_type' in query_params:
|
||||
params = {
|
||||
'establishments__isnull': False,
|
||||
}
|
||||
elif 'product_type' in query_params:
|
||||
params = {
|
||||
'products__isnull': False,
|
||||
}
|
||||
|
||||
tags = obj.tags.filter(**params).distinct()
|
||||
return TagBaseSerializer(instance=tags, many=True, read_only=True).data
|
||||
|
||||
|
||||
class TagCategoryShortSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for model TagCategory."""
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ app_name = 'tag'
|
|||
|
||||
router = SimpleRouter()
|
||||
router.register(r'categories', views.TagCategoryViewSet)
|
||||
router.register(r'filters', views.FiltersTagCategoryViewSet)
|
||||
router.register(r'chosen_tags', views.ChosenTagsView)
|
||||
|
||||
urlpatterns = [
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
"""Tag views."""
|
||||
from django.conf import settings
|
||||
from rest_framework import generics
|
||||
from rest_framework import mixins
|
||||
from rest_framework import permissions
|
||||
from rest_framework import viewsets, mixins, status, generics
|
||||
from rest_framework import status
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
||||
from tag import filters, models, serializers
|
||||
from location.models import WineRegion
|
||||
from tag import filters
|
||||
from tag import models
|
||||
from tag import serializers
|
||||
|
||||
|
||||
class ChosenTagsView(generics.ListAPIView, viewsets.GenericViewSet):
|
||||
|
|
@ -36,7 +42,8 @@ class ChosenTagsView(generics.ListAPIView, viewsets.GenericViewSet):
|
|||
serializer = self.get_serializer(queryset, many=True)
|
||||
result_list = serializer.data
|
||||
if request.query_params.get('type') and (settings.ESTABLISHMENT_CHOSEN_TAGS or settings.NEWS_CHOSEN_TAGS):
|
||||
ordered_list = settings.ESTABLISHMENT_CHOSEN_TAGS if request.query_params.get('type') == 'establishment' else settings.NEWS_CHOSEN_TAGS
|
||||
ordered_list = settings.ESTABLISHMENT_CHOSEN_TAGS if request.query_params.get(
|
||||
'type') == 'establishment' else settings.NEWS_CHOSEN_TAGS
|
||||
result_list = sorted(result_list, key=lambda x: ordered_list.index(x['index_name']))
|
||||
return Response(result_list)
|
||||
|
||||
|
|
@ -53,6 +60,139 @@ class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
|||
serializer_class = serializers.TagCategoryBaseSerializer
|
||||
|
||||
|
||||
# User`s views & viewsets
|
||||
class FiltersTagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
||||
"""ViewSet for TagCategory model."""
|
||||
|
||||
filterset_class = filters.TagCategoryFilterSet
|
||||
pagination_class = None
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
queryset = models.TagCategory.objects.with_tags().with_base_related(). \
|
||||
distinct()
|
||||
serializer_class = serializers.FiltersTagCategoryBaseSerializer
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
serializer = self.get_serializer(queryset, many=True)
|
||||
|
||||
result_list = serializer.data
|
||||
query_params = request.query_params
|
||||
|
||||
params_type = query_params.get('type')
|
||||
if query_params.get('establishment_type'):
|
||||
params_type = query_params.get('establishment_type')
|
||||
elif query_params.get('product_type'):
|
||||
params_type = query_params.get('product_type')
|
||||
|
||||
week_days = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
|
||||
flags = ('toque_number', 'wine_region', 'works_noon', 'works_evening', 'works_now', 'works_at_weekday')
|
||||
filter_flags = {flag_name: False for flag_name in flags}
|
||||
additional_flags = []
|
||||
|
||||
if params_type == 'restaurant':
|
||||
additional_flags += ['toque_number', 'works_noon', 'works_evening', 'works_now']
|
||||
|
||||
elif params_type == 'winery':
|
||||
additional_flags += ['wine_region']
|
||||
|
||||
elif params_type == 'artisan':
|
||||
additional_flags += ['works_now', 'works_at_weekday']
|
||||
|
||||
for flag_name in additional_flags:
|
||||
filter_flags[flag_name] = True
|
||||
|
||||
if filter_flags['toque_number']:
|
||||
toques = {
|
||||
"index_name": "toque_number",
|
||||
"label_translated": "Toques",
|
||||
"param_name": "toque_number__in",
|
||||
"filters": [{
|
||||
"id": toque_id,
|
||||
"index_name": "toque_%d" % toque_id,
|
||||
"label_translated": "Toque %d" % toque_id
|
||||
} for toque_id in range(6)]
|
||||
}
|
||||
result_list.append(toques)
|
||||
|
||||
if filter_flags['wine_region']:
|
||||
wine_region_id = query_params.get('wine_region_id__in')
|
||||
|
||||
if str(wine_region_id).isdigit():
|
||||
queryset = WineRegion.objects.filter(id=int(wine_region_id))
|
||||
|
||||
else:
|
||||
queryset = WineRegion.objects.all()
|
||||
|
||||
wine_regions = {
|
||||
"index_name": "wine_region",
|
||||
"label_translated": "Wine region",
|
||||
"param_name": "wine_region_id__in",
|
||||
"filters": [{
|
||||
"id": obj.id,
|
||||
"index_name": obj.name.lower().replace(' ', '_'),
|
||||
"label_translated": obj.name
|
||||
} for obj in queryset]
|
||||
}
|
||||
|
||||
result_list.append(wine_regions)
|
||||
|
||||
if filter_flags['works_noon']:
|
||||
works_noon = {
|
||||
"index_name": "works_noon",
|
||||
"label_translated": "Open noon",
|
||||
"param_name": "works_noon__in",
|
||||
"filters": [{
|
||||
"id": weekday,
|
||||
"index_name": week_days[weekday].lower(),
|
||||
"label_translated": week_days[weekday]
|
||||
} for weekday in range(7)]
|
||||
}
|
||||
result_list.append(works_noon)
|
||||
|
||||
if filter_flags['works_evening']:
|
||||
|
||||
works_evening = {
|
||||
"index_name": "works_evening",
|
||||
"label_translated": "Open evening",
|
||||
"param_name": "works_evening__in",
|
||||
"filters": [{
|
||||
"id": weekday,
|
||||
"index_name": week_days[weekday].lower(),
|
||||
"label_translated": week_days[weekday]
|
||||
} for weekday in range(7)]
|
||||
}
|
||||
result_list.append(works_evening)
|
||||
|
||||
if filter_flags['works_now']:
|
||||
works_now = {
|
||||
"index_name": "open_now",
|
||||
"label_translated": "Open now",
|
||||
"param_name": "open_now",
|
||||
"type": True
|
||||
}
|
||||
result_list.append(works_now)
|
||||
|
||||
if filter_flags['works_at_weekday']:
|
||||
works_at_weekday = {
|
||||
"index_name": "works_at_weekday",
|
||||
"label_translated": "Works at weekday",
|
||||
"param_name": "works_at_weekday__in",
|
||||
"filters": [{
|
||||
"id": weekday,
|
||||
"index_name": week_days[weekday].lower(),
|
||||
"label_translated": week_days[weekday]
|
||||
} for weekday in range(7)]
|
||||
}
|
||||
result_list.append(works_at_weekday)
|
||||
|
||||
if 'tags_id__in' in query_params:
|
||||
# filtering by params_type and tags id
|
||||
# todo: result_list.append( filtering_data )
|
||||
pass
|
||||
|
||||
return Response(result_list)
|
||||
|
||||
|
||||
# BackOffice user`s views & viewsets
|
||||
class BindObjectMixin:
|
||||
"""Bind object mixin."""
|
||||
|
|
|
|||
|
|
@ -516,9 +516,6 @@ PHONENUMBER_DEFAULT_REGION = "FR"
|
|||
|
||||
FALLBACK_LOCALE = 'en-GB'
|
||||
|
||||
# TMP TODO remove it later
|
||||
# Временный хардкод для демонстрации > 15 ноября, потом удалить!
|
||||
CAROUSEL_ITEMS = [465]
|
||||
ESTABLISHMENT_CHOSEN_TAGS = ['gastronomic', 'en_vogue', 'terrace', 'streetfood', 'business', 'bar_cocktail', 'brunch', 'pop']
|
||||
NEWS_CHOSEN_TAGS = ['eat', 'drink', 'cook', 'style', 'international', 'event', 'partnership']
|
||||
INTERNATIONAL_COUNTRY_CODES = ['www', 'main', 'next']
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user