From 8fb8c49bfe9e0b88c7f76185e99a1f3bf7313048 Mon Sep 17 00:00:00 2001 From: dormantman Date: Wed, 22 Jan 2020 18:48:16 +0300 Subject: [PATCH 001/101] Added employee positions method --- apps/establishment/serializers/back.py | 13 +++++++++++ apps/establishment/urls/back.py | 4 +++- apps/establishment/views/back.py | 30 ++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 4000bef9..b09f17a9 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -92,6 +92,19 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria return instance +class EstablishmentPositionListSerializer(model_serializers.EstablishmentBaseSerializer): + """Establishment position serializer""" + + class Meta: + model = models.Establishment + fields = [ + 'id', + 'name', + 'transliterated_name', + 'index_name', + ] + + class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): """Establishment create serializer""" diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index 00d44fc2..4769e332 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -57,6 +57,8 @@ urlpatterns = [ path('subtypes/', views.EstablishmentSubtypeListCreateView.as_view(), name='subtype-list'), path('subtypes//', views.EstablishmentSubtypeRUDView.as_view(), name='subtype-rud'), path('positions/', views.EstablishmentPositionListView.as_view(), name='position-list'), + path('employee_positions//', views.EmployeePositionsListView.as_view(), + name='employee-positions-list'), path('employee_establishments//', views.EmployeeEstablishmentsListView.as_view(), - name='employee-establishments-list') + name='employee-establishments-list'), ] diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 4bbf9533..60642130 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -4,10 +4,12 @@ from django.http import Http404 from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend from rest_framework import generics, permissions +from rest_framework.response import Response from account.models import User from establishment import filters, models, serializers from establishment.models import EstablishmentEmployee +from establishment.serializers import PositionBackSerializer from timetable.models import Timetable from timetable.serialziers import ScheduleCreateSerializer, ScheduleRUDSerializer from utils.permissions import IsCountryAdmin, IsEstablishmentManager, IsWineryReviewer @@ -45,6 +47,34 @@ class EmployeeEstablishmentsListView(generics.ListAPIView): return employee.establishments.with_extended_related() +class EmployeePositionsListView(generics.ListAPIView): + """Establishment position by employee list view.""" + + permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager] + queryset = models.Establishment.objects.all() + serializer_class = serializers.EstablishmentPositionListSerializer + + def list(self, request, *args, **kwargs): + pk = self.kwargs.get('pk') + employee = get_object_or_404(models.Employee, pk=pk) + + queryset = employee.establishments.with_extended_related() + queryset = self.filter_queryset(queryset) + + data = PositionBackSerializer( + employee.establishmentemployee_set.all().values_list('position', flat=True), many=True + ).data + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + + serializer = self.get_serializer(queryset, many=True) + + return Response(serializer.data) + + class EstablishmentRUDView(generics.RetrieveUpdateDestroyAPIView): lookup_field = 'slug' queryset = models.Establishment.objects.all().prefetch_related( From 62ab6248ba9544b3c67c8c70e7ae737d9e988ffa Mon Sep 17 00:00:00 2001 From: dormantman Date: Fri, 24 Jan 2020 17:41:43 +0300 Subject: [PATCH 002/101] Fix subscribes --- .../migrations/0011_auto_20200124_1351.py | 39 +++++++++++++++++++ apps/notification/models.py | 31 ++++++++++++--- apps/notification/serializers/common.py | 11 ++++++ apps/notification/tasks.py | 1 - apps/notification/views/common.py | 2 +- 5 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 apps/notification/migrations/0011_auto_20200124_1351.py diff --git a/apps/notification/migrations/0011_auto_20200124_1351.py b/apps/notification/migrations/0011_auto_20200124_1351.py new file mode 100644 index 00000000..5b86c7ec --- /dev/null +++ b/apps/notification/migrations/0011_auto_20200124_1351.py @@ -0,0 +1,39 @@ +# Generated by Django 2.2.7 on 2020-01-24 13:51 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('notification', '0010_auto_20191231_0135'), + ] + + operations = [ + migrations.AddField( + model_name='subscribe', + name='old_subscriber_id', + field=models.PositiveIntegerField(null=True, verbose_name='Old subscriber id'), + ), + migrations.AddField( + model_name='subscribe', + name='old_subscription_type_id', + field=models.PositiveIntegerField(null=True, verbose_name='Old subscription type id'), + ), + migrations.AlterField( + model_name='subscribe', + name='subscribe_date', + field=models.DateTimeField(blank=True, default=None, null=True, verbose_name='Last subscribe date'), + ), + migrations.AlterField( + model_name='subscribe', + name='subscriber', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='notification.Subscriber'), + ), + migrations.AlterField( + model_name='subscribe', + name='subscription_type', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='notification.SubscriptionType'), + ), + ] diff --git a/apps/notification/models.py b/apps/notification/models.py index e0855c62..6f1ab33c 100644 --- a/apps/notification/models.py +++ b/apps/notification/models.py @@ -2,6 +2,7 @@ from django.conf import settings from django.db import models +from django.db.models import F from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ @@ -10,6 +11,7 @@ from location.models import Country from notification.tasks import send_unsubscribe_email from utils.methods import generate_string_code from utils.models import ProjectBaseMixin, TJSONField, TranslatedFieldsMixin +from notification.tasks import send_unsubscribe_email class SubscriptionType(ProjectBaseMixin, TranslatedFieldsMixin): @@ -133,7 +135,12 @@ class Subscriber(ProjectBaseMixin): def unsubscribe(self, query: dict): """Unsubscribe user.""" - self.subscribe_set.update(unsubscribe_date=now()) + + self.subscribe_set.update( + unsunbscribe_date=now(), + old_subscriber_id=F('subscriber_id'), + old_subscription_type_id=F('subscription_type_id') + ).update(subscriber_id=None, subscription_type_id=None) if settings.USE_CELERY: send_unsubscribe_email.delay(self.email) @@ -166,15 +173,20 @@ class SubscribeQuerySet(models.QuerySet): """Fetches active subscriptions.""" return self.exclude(unsubscribe_date__isnull=not switcher) + def subscription_history(self, subscriber_id: int): + return self.filter(old_subscriber_id=subscriber_id) + class Subscribe(ProjectBaseMixin): """Subscribe model.""" - - subscribe_date = models.DateTimeField(_('Last subscribe date'), blank=True, null=True, default=now) + subscribe_date = models.DateTimeField(_('Last subscribe date'), default=now(), blank=True, null=True) unsubscribe_date = models.DateTimeField(_('Last unsubscribe date'), blank=True, null=True, default=None) - subscriber = models.ForeignKey(Subscriber, on_delete=models.CASCADE) - subscription_type = models.ForeignKey(SubscriptionType, on_delete=models.CASCADE) + subscriber = models.ForeignKey(Subscriber, on_delete=models.CASCADE, null=True) + subscription_type = models.ForeignKey(SubscriptionType, on_delete=models.CASCADE, null=True) + + old_subscriber_id = models.PositiveIntegerField(_("Old subscriber id"), null=True) + old_subscription_type_id = models.PositiveIntegerField(_("Old subscription type id"), null=True) objects = SubscribeQuerySet.as_manager() @@ -183,3 +195,12 @@ class Subscribe(ProjectBaseMixin): verbose_name = _('Subscribe') verbose_name_plural = _('Subscribes') + + def save(self, *args, **kwargs): + if self.subscriber is not None: + self.old_subscriber_id = self.subscriber.pk + + if self.subscription_type is not None: + self.old_subscription_type_id = self.subscription_type.pk + + return super().save(*args, **kwargs) diff --git a/apps/notification/serializers/common.py b/apps/notification/serializers/common.py index 869879cb..48caee48 100644 --- a/apps/notification/serializers/common.py +++ b/apps/notification/serializers/common.py @@ -166,3 +166,14 @@ class SubscribeSerializer(serializers.ModelSerializer): 'subscription_types', 'link_to_unsubscribe', ) + + +class UnsubscribeSerializer(serializers.ModelSerializer): + email = serializers.EmailField(read_only=True, required=False, source='send_to') + subscription_types = SubscriptionTypeSerializer(source='active_subscriptions', read_only=True, many=True) + + class Meta: + """Meta class.""" + + model = models.Subscriber + fields = SubscribeSerializer.Meta.fields diff --git a/apps/notification/tasks.py b/apps/notification/tasks.py index 790c9650..3f9f7249 100644 --- a/apps/notification/tasks.py +++ b/apps/notification/tasks.py @@ -3,7 +3,6 @@ from datetime import datetime from celery import shared_task from django.conf import settings from django.core.mail import send_mail -from django.utils.translation import gettext_lazy as _ from django.template.loader import get_template, render_to_string from main.models import SiteSettings diff --git a/apps/notification/views/common.py b/apps/notification/views/common.py index b6584394..bb6c9d6b 100644 --- a/apps/notification/views/common.py +++ b/apps/notification/views/common.py @@ -70,7 +70,7 @@ class UnsubscribeView(generics.UpdateAPIView): queryset = models.Subscriber.objects.all() serializer_class = serializers.SubscribeSerializer - def patch(self, request, *args, **kw): + def put(self, request, *args, **kw): obj = self.get_object() obj.unsubscribe(request.query_params) serializer = self.get_serializer(instance=obj) From 5a1d33c981d700fe3c281d791e8d0dcfd24d8a66 Mon Sep 17 00:00:00 2001 From: dormantman Date: Fri, 24 Jan 2020 17:52:47 +0300 Subject: [PATCH 003/101] Remove save --- apps/notification/models.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/notification/models.py b/apps/notification/models.py index 6f1ab33c..adcb4fab 100644 --- a/apps/notification/models.py +++ b/apps/notification/models.py @@ -195,12 +195,3 @@ class Subscribe(ProjectBaseMixin): verbose_name = _('Subscribe') verbose_name_plural = _('Subscribes') - - def save(self, *args, **kwargs): - if self.subscriber is not None: - self.old_subscriber_id = self.subscriber.pk - - if self.subscription_type is not None: - self.old_subscription_type_id = self.subscription_type.pk - - return super().save(*args, **kwargs) From c82362b268fde5b7f28203e5932599ed61867e02 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Fri, 24 Jan 2020 17:54:30 +0300 Subject: [PATCH 004/101] should_read same country --- apps/news/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/news/models.py b/apps/news/models.py index 89dacf5a..2316fc27 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -136,6 +136,7 @@ class NewsQuerySet(TranslationQuerysetMixin): def should_read(self, news, user): return self.model.objects.exclude(pk=news.pk).published(). \ annotate_in_favorites(user). \ + filter(country=news.country). \ with_base_related().by_type(news.news_type).distinct().order_by('?') def same_theme(self, news, user): From 0f73cf94779d414858fd545c2258d5b66f1fa624 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Fri, 24 Jan 2020 18:08:51 +0300 Subject: [PATCH 005/101] fix news agenda --- apps/news/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 564cd2c9..6e9781db 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -207,7 +207,7 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer): """News back office base serializer.""" is_published = serializers.BooleanField(source='is_publish', read_only=True) descriptions = serializers.ListField(required=False) - agenda = AgendaSerializer() + agenda = AgendaSerializer(required=False, allow_null=True) class Meta(NewsBaseSerializer.Meta): """Meta class.""" From 0ad1408f18029e1bb4b613abf6d80912366f63e1 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 24 Jan 2020 18:12:53 +0300 Subject: [PATCH 006/101] added account removal action --- apps/account/views/common.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/account/views/common.py b/apps/account/views/common.py index 8b066742..e242c393 100644 --- a/apps/account/views/common.py +++ b/apps/account/views/common.py @@ -17,7 +17,7 @@ from utils.views import JWTGenericViewMixin # User views -class UserRetrieveUpdateView(generics.RetrieveUpdateAPIView): +class UserRetrieveUpdateView(generics.RetrieveUpdateDestroyAPIView): """User update view.""" serializer_class = serializers.UserSerializer queryset = models.User.objects.active() @@ -25,6 +25,10 @@ class UserRetrieveUpdateView(generics.RetrieveUpdateAPIView): def get_object(self): return self.request.user + def delete(self, request, *args, **kwargs): + """Overridden behavior of DELETE method.""" + return Response(status=status.HTTP_204_NO_CONTENT) + class ChangePasswordView(generics.GenericAPIView): """Change password view""" From 8acb86a5ab30f67fafb635c1e5f14e97d50706bb Mon Sep 17 00:00:00 2001 From: dormantman Date: Fri, 24 Jan 2020 18:25:17 +0300 Subject: [PATCH 007/101] Added history to subscriptions --- apps/notification/models.py | 12 ++++++++++-- apps/notification/serializers/common.py | 20 ++++++++++++++++---- apps/notification/tasks.py | 1 + 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/apps/notification/models.py b/apps/notification/models.py index adcb4fab..094fcad4 100644 --- a/apps/notification/models.py +++ b/apps/notification/models.py @@ -137,10 +137,14 @@ class Subscriber(ProjectBaseMixin): """Unsubscribe user.""" self.subscribe_set.update( - unsunbscribe_date=now(), + unsubscribe_date=now(), old_subscriber_id=F('subscriber_id'), old_subscription_type_id=F('subscription_type_id') - ).update(subscriber_id=None, subscription_type_id=None) + ) + self.subscribe_set.update( + subscriber_id=None, + subscription_type_id=None + ) if settings.USE_CELERY: send_unsubscribe_email.delay(self.email) @@ -166,6 +170,10 @@ class Subscriber(ProjectBaseMixin): def active_subscriptions(self): return self.subscription_types.exclude(subscriber__subscribe__unsubscribe_date__isnull=False) + @property + def subscription_history(self): + return Subscribe.objects.subscription_history(self.pk) + class SubscribeQuerySet(models.QuerySet): diff --git a/apps/notification/serializers/common.py b/apps/notification/serializers/common.py index 48caee48..9eda31b3 100644 --- a/apps/notification/serializers/common.py +++ b/apps/notification/serializers/common.py @@ -141,14 +141,24 @@ class UpdateSubscribeSerializer(serializers.ModelSerializer): class SubscribeObjectSerializer(serializers.ModelSerializer): - """Subscribe serializer.""" + """Subscription type serializer.""" + + subscription_type = serializers.SerializerMethodField() class Meta: """Meta class.""" - model = models.Subscriber - fields = ('subscriber',) - read_only_fields = ('subscribe_date', 'unsubscribe_date',) + model = models.Subscribe + fields = ( + 'subscribe_date', + 'unsubscribe_date', + 'subscription_type' + ) + + def get_subscription_type(self, instance): + return SubscriptionTypeSerializer( + models.SubscriptionType.objects.get(pk=instance.old_subscription_type_id) + ).data class SubscribeSerializer(serializers.ModelSerializer): @@ -156,6 +166,7 @@ class SubscribeSerializer(serializers.ModelSerializer): email = serializers.EmailField(required=False, source='send_to') subscription_types = SubscriptionTypeSerializer(source='active_subscriptions', read_only=True, many=True) + history = SubscribeObjectSerializer(source='subscription_history', many=True) class Meta: """Meta class.""" @@ -165,6 +176,7 @@ class SubscribeSerializer(serializers.ModelSerializer): 'email', 'subscription_types', 'link_to_unsubscribe', + 'history', ) diff --git a/apps/notification/tasks.py b/apps/notification/tasks.py index 3f9f7249..cea15287 100644 --- a/apps/notification/tasks.py +++ b/apps/notification/tasks.py @@ -7,6 +7,7 @@ from django.template.loader import get_template, render_to_string from main.models import SiteSettings from notification import models +from django.utils.translation import gettext_lazy as _ @shared_task From e998865de58bb06f23142ec0e8c559d6c887e0e0 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Fri, 24 Jan 2020 18:49:01 +0300 Subject: [PATCH 008/101] try to fix subscriptions --- apps/notification/serializers/common.py | 8 ++++++++ apps/notification/views/common.py | 15 ++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/notification/serializers/common.py b/apps/notification/serializers/common.py index 869879cb..67787b2e 100644 --- a/apps/notification/serializers/common.py +++ b/apps/notification/serializers/common.py @@ -95,6 +95,14 @@ class CreateAndUpdateSubscribeSerializer(serializers.ModelSerializer): return subscriber + def update(self, instance, validated_data): + if settings.USE_CELERY: + send_subscribes_update_email.delay(instance.pk) + else: + send_subscribes_update_email(instance.pk) + + return super().update(instance, validated_data) + class UpdateSubscribeSerializer(serializers.ModelSerializer): """Update with code Subscribe serializer.""" diff --git a/apps/notification/views/common.py b/apps/notification/views/common.py index a0534d13..d41ef22c 100644 --- a/apps/notification/views/common.py +++ b/apps/notification/views/common.py @@ -1,6 +1,6 @@ """Notification app common views.""" from django.shortcuts import get_object_or_404 -from rest_framework import generics, permissions +from rest_framework import generics, permissions, status from rest_framework.response import Response from notification import models @@ -15,6 +15,19 @@ class CreateSubscribeView(generics.CreateAPIView): permission_classes = (permissions.AllowAny,) serializer_class = serializers.CreateAndUpdateSubscribeSerializer + def create(self, request, *args, **kwargs): + data = request.data + if 'email' in request.data: + # we shouldn't create new subscriber if we have one + subscriber = models.Subscriber.objects.filter(email=request.data['email']).first() + if subscriber: + data = subscriber # new serializer will simply update instance instead of creating another one + serializer = self.get_serializer(data=data) + serializer.is_valid(raise_exception=True) + self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + class UpdateSubscribeView(generics.UpdateAPIView): """Subscribe info view.""" From 03946d0626e870f75b9c1291691995dd4dcf54c4 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Fri, 24 Jan 2020 18:52:36 +0300 Subject: [PATCH 009/101] try to fix subscriptions #2 --- apps/notification/views/common.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/notification/views/common.py b/apps/notification/views/common.py index d41ef22c..375826e1 100644 --- a/apps/notification/views/common.py +++ b/apps/notification/views/common.py @@ -17,12 +17,11 @@ class CreateSubscribeView(generics.CreateAPIView): def create(self, request, *args, **kwargs): data = request.data + instance = None if 'email' in request.data: # we shouldn't create new subscriber if we have one - subscriber = models.Subscriber.objects.filter(email=request.data['email']).first() - if subscriber: - data = subscriber # new serializer will simply update instance instead of creating another one - serializer = self.get_serializer(data=data) + instance = models.Subscriber.objects.filter(email=request.data['email']).first() + serializer = self.get_serializer(data=data) if instance is None else self.get_serializer(instance, data=data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) From 2e4daaf9a1c3919ad6275261518c6715ad244ac6 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Fri, 24 Jan 2020 19:02:22 +0300 Subject: [PATCH 010/101] try to fix subscriptions #3 --- apps/notification/serializers/common.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/notification/serializers/common.py b/apps/notification/serializers/common.py index 67787b2e..7c22f713 100644 --- a/apps/notification/serializers/common.py +++ b/apps/notification/serializers/common.py @@ -40,6 +40,7 @@ class CreateAndUpdateSubscribeSerializer(serializers.ModelSerializer): model = models.Subscriber fields = ( + 'id', 'email', 'subscription_types', 'link_to_unsubscribe', @@ -54,7 +55,7 @@ class CreateAndUpdateSubscribeSerializer(serializers.ModelSerializer): user = request.user # validate email - email = attrs.get('send_to') + email = attrs.pop('send_to') if attrs.get('email'): email = attrs.get('email') From 809b5ccab72100d77081e24aa8e53c061898fe6a Mon Sep 17 00:00:00 2001 From: dormantman Date: Fri, 24 Jan 2020 22:33:39 +0300 Subject: [PATCH 011/101] Fixed employee establishments method --- apps/establishment/serializers/back.py | 20 ++++++++++++++++++++ apps/establishment/views/back.py | 8 +++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index b09f17a9..fcb1c518 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -526,3 +526,23 @@ class EstablishmentAdminListSerializer(UserShortSerializer): 'username', 'email' ] + + +class EstablishmentEmployeeListSerializer(serializers.ModelSerializer): + """Establishments from employee serializer""" + + restaurant = EstablishmentListCreateSerializer(read_only=True, source='establishment') + position = PositionBackSerializer(read_only=True) + state = serializers.CharField(read_only=True, source='status') + start = serializers.DateTimeField(read_only=True, source='from_date') + end = serializers.DateTimeField(read_only=True, source='to_date') + + class Meta: + model = models.EstablishmentEmployee + fields = [ + 'restaurant', + 'position', + 'state', + 'start', + 'end', + ] diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 60642130..e8600b97 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -1,6 +1,4 @@ """Establishment app views.""" -from django.core.exceptions import ObjectDoesNotExist -from django.http import Http404 from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend from rest_framework import generics, permissions @@ -38,13 +36,13 @@ class EmployeeEstablishmentsListView(generics.ListAPIView): """Establishment by employee list view.""" permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager] - queryset = models.Establishment.objects.all() - serializer_class = serializers.EstablishmentListCreateSerializer + queryset = models.EstablishmentEmployee.objects.all() + serializer_class = serializers.EstablishmentEmployeeListSerializer def get_queryset(self): pk = self.kwargs.get('pk') employee = get_object_or_404(models.Employee, pk=pk) - return employee.establishments.with_extended_related() + return employee.establishmentemployee_set.all() class EmployeePositionsListView(generics.ListAPIView): From dd49ee7b6c0775d06db40628068a117ac098d045 Mon Sep 17 00:00:00 2001 From: dormantman Date: Fri, 24 Jan 2020 22:37:06 +0300 Subject: [PATCH 012/101] Reformat restaurant to name --- apps/establishment/serializers/back.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index fcb1c518..dbcaebfa 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -531,7 +531,7 @@ class EstablishmentAdminListSerializer(UserShortSerializer): class EstablishmentEmployeeListSerializer(serializers.ModelSerializer): """Establishments from employee serializer""" - restaurant = EstablishmentListCreateSerializer(read_only=True, source='establishment') + restaurant_name = serializers.CharField(read_only=True, source='establishment.name') position = PositionBackSerializer(read_only=True) state = serializers.CharField(read_only=True, source='status') start = serializers.DateTimeField(read_only=True, source='from_date') @@ -540,7 +540,7 @@ class EstablishmentEmployeeListSerializer(serializers.ModelSerializer): class Meta: model = models.EstablishmentEmployee fields = [ - 'restaurant', + 'restaurant_name', 'position', 'state', 'start', From d2f04d4958c89d1e14f04d63d408d25db47277cd Mon Sep 17 00:00:00 2001 From: dormantman Date: Sat, 25 Jan 2020 00:42:00 +0300 Subject: [PATCH 013/101] Reformat method structure --- apps/establishment/serializers/back.py | 2 -- apps/establishment/views/back.py | 27 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index dbcaebfa..95b1050f 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -531,7 +531,6 @@ class EstablishmentAdminListSerializer(UserShortSerializer): class EstablishmentEmployeeListSerializer(serializers.ModelSerializer): """Establishments from employee serializer""" - restaurant_name = serializers.CharField(read_only=True, source='establishment.name') position = PositionBackSerializer(read_only=True) state = serializers.CharField(read_only=True, source='status') start = serializers.DateTimeField(read_only=True, source='from_date') @@ -540,7 +539,6 @@ class EstablishmentEmployeeListSerializer(serializers.ModelSerializer): class Meta: model = models.EstablishmentEmployee fields = [ - 'restaurant_name', 'position', 'state', 'start', diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index e8600b97..eef93e18 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -1,4 +1,6 @@ """Establishment app views.""" +from collections import defaultdict + from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend from rest_framework import generics, permissions @@ -39,10 +41,27 @@ class EmployeeEstablishmentsListView(generics.ListAPIView): queryset = models.EstablishmentEmployee.objects.all() serializer_class = serializers.EstablishmentEmployeeListSerializer - def get_queryset(self): + def list(self, request, *args, **kwargs): pk = self.kwargs.get('pk') employee = get_object_or_404(models.Employee, pk=pk) - return employee.establishmentemployee_set.all() + + preload_data = defaultdict(list) + for establishment_employee in employee.establishmentemployee_set.all() \ + .prefetch_related('establishment').select_related('position'): + establishment_name = establishment_employee.establishment.name + + preload_data[establishment_name].append( + serializers.EstablishmentEmployeeListSerializer(establishment_employee).data + ) + + data = [{ + 'restaurant_name': establishment_name, + 'positions': [ + preload_data[establishment_name] + ] + } for establishment_name in preload_data] + + return Response(data) class EmployeePositionsListView(generics.ListAPIView): @@ -59,10 +78,6 @@ class EmployeePositionsListView(generics.ListAPIView): queryset = employee.establishments.with_extended_related() queryset = self.filter_queryset(queryset) - data = PositionBackSerializer( - employee.establishmentemployee_set.all().values_list('position', flat=True), many=True - ).data - page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) From 1d3cf9dac0ef1698b15ee76dfaf0d115a6b14181 Mon Sep 17 00:00:00 2001 From: "a.gorbunov" Date: Mon, 27 Jan 2020 06:41:52 +0000 Subject: [PATCH 014/101] select related before load --- apps/collection/models.py | 4 ++++ apps/collection/views/back.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/collection/models.py b/apps/collection/models.py index 0457f38d..8024effb 100644 --- a/apps/collection/models.py +++ b/apps/collection/models.py @@ -57,6 +57,10 @@ class CollectionQuerySet(RelatedObjectsCountMixin): """Returned only published collection""" return self.filter(is_publish=True) + def with_base_related(self): + """Select relate objects""" + return self.select_related('country') + class Collection(ProjectBaseMixin, CollectionDateMixin, TranslatedFieldsMixin, URLImageMixin): diff --git a/apps/collection/views/back.py b/apps/collection/views/back.py index 481f70da..032bafb3 100644 --- a/apps/collection/views/back.py +++ b/apps/collection/views/back.py @@ -75,7 +75,7 @@ class CollectionBackOfficeViewSet(mixins.CreateModelMixin, """ViewSet for Collection model for BackOffice users.""" permission_classes = (permissions.IsAuthenticated,) - queryset = models.Collection.objects.all() + queryset = models.Collection.objects.with_base_related() filter_backends = [DjangoFilterBackend, OrderingFilter] serializer_class = serializers.CollectionBackOfficeSerializer bind_object_serializer_class = serializers.CollectionBindObjectSerializer From bcecb39ee29c2151d34a36381994d86f9424f03b Mon Sep 17 00:00:00 2001 From: Anatoly Date: Mon, 27 Jan 2020 11:11:24 +0300 Subject: [PATCH 015/101] disable checking on email field in UserDetailSerializer --- apps/account/serializers/common.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/account/serializers/common.py b/apps/account/serializers/common.py index 9ca3caf0..6722e539 100644 --- a/apps/account/serializers/common.py +++ b/apps/account/serializers/common.py @@ -122,12 +122,6 @@ class UserSerializer(serializers.ModelSerializer): subscriptions_handler(subscriptions_list, user) return user - def validate_email(self, value): - """Validate email value""" - if hasattr(self.instance, 'email') and self.instance.email and value == self.instance.email: - raise serializers.ValidationError(detail='Equal email address.') - return value - def validate_username(self, value): """Custom username validation""" valid = utils_methods.username_validator(username=value) @@ -141,12 +135,13 @@ class UserSerializer(serializers.ModelSerializer): if 'subscription_types' in validated_data: subscriptions_list = validated_data.pop('subscription_types') + new_email = validated_data.get('email') old_email = instance.email instance = super().update(instance, validated_data) - if 'email' in validated_data: + if new_email and new_email != old_email: instance.email_confirmed = False instance.email = old_email - instance.unconfirmed_email = validated_data['email'] + instance.unconfirmed_email = new_email instance.save() # Send verification link on user email for change email address if settings.USE_CELERY: From 7386887f491c30b9d27fb98148e7951aeeebba79 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 11:24:59 +0300 Subject: [PATCH 016/101] state fields for BO --- apps/news/serializers.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 6e9781db..76b55ae6 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -208,6 +208,7 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer): is_published = serializers.BooleanField(source='is_publish', read_only=True) descriptions = serializers.ListField(required=False) agenda = AgendaSerializer(required=False, allow_null=True) + state_display = serializers.CharField(source='get_state_display', read_only=True) class Meta(NewsBaseSerializer.Meta): """Meta class.""" @@ -226,7 +227,9 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer): 'created', 'modified', 'descriptions', - 'agenda' + 'agenda', + 'state', + 'state_display', ) extra_kwargs = { 'created': {'read_only': True}, @@ -234,6 +237,8 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer): 'duplication_date': {'read_only': True}, 'locale_to_description_is_active': {'allow_null': False}, 'must_of_the_week': {'read_only': True}, + 'state': {'read_only': True}, + 'state_display': {'read_only': True}, } def validate(self, attrs): From b1817061dbd000ae788d1a0a06e09dd2523665c7 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 12:53:37 +0300 Subject: [PATCH 017/101] try to fix subscriptions #4 --- apps/notification/views/common.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/apps/notification/views/common.py b/apps/notification/views/common.py index 375826e1..9562b922 100644 --- a/apps/notification/views/common.py +++ b/apps/notification/views/common.py @@ -56,20 +56,7 @@ class SubscribeInfoAuthUserView(generics.RetrieveAPIView): lookup_field = None def get_object(self): - user = self.request.user - - subscriber = models.Subscriber.objects.filter(user=user).first() - - if subscriber is None: - subscriber = models.Subscriber.objects.make_subscriber( - email=user.email, user=user, ip_address=get_user_ip(self.request), - country_code=self.request.country_code, locale=self.request.locale - ) - - else: - return get_object_or_404(models.Subscriber, user=user) - - return subscriber + return get_object_or_404(models.Subscriber, user=self.request.user) class UnsubscribeView(generics.UpdateAPIView): From e1c16628197c9bae27b812a838d77a7259947ff7 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Mon, 27 Jan 2020 13:19:36 +0300 Subject: [PATCH 018/101] refactored filters for partner view --- apps/partner/filters.py | 23 +++++++++++++++++++++++ apps/partner/views/back.py | 12 +++++------- 2 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 apps/partner/filters.py diff --git a/apps/partner/filters.py b/apps/partner/filters.py new file mode 100644 index 00000000..e9b32f5f --- /dev/null +++ b/apps/partner/filters.py @@ -0,0 +1,23 @@ +"""Partner app filters.""" +from django_filters import rest_framework as filters + +from partner.models import Partner + + +class PartnerFilterSet(filters.FilterSet): + """Establishment filter set.""" + + establishment = filters.NumberFilter( + help_text='Allows to get partner list by establishment ID.') + type = filters.ChoiceFilter( + choices=Partner.MODEL_TYPES, + help_text=f'Allows to filter partner list by partner type. ' + f'Enum: {dict(Partner.MODEL_TYPES)}') + + class Meta: + """Meta class.""" + model = Partner + fields = ( + 'establishment', + 'type', + ) diff --git a/apps/partner/views/back.py b/apps/partner/views/back.py index 1033d0ee..7ea440f0 100644 --- a/apps/partner/views/back.py +++ b/apps/partner/views/back.py @@ -1,22 +1,20 @@ -from django_filters.rest_framework import DjangoFilterBackend, filters from rest_framework import generics, permissions +from partner import filters from partner.models import Partner from partner.serializers import back as serializers from utils.permissions import IsEstablishmentManager class PartnerLstView(generics.ListCreateAPIView): - """Partner list create view.""" + """Partner list/create view. + Allows to get partners for current country, or create a new one. + """ queryset = Partner.objects.all() serializer_class = serializers.BackPartnerSerializer pagination_class = None permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] - filter_backends = (DjangoFilterBackend,) - filterset_fields = ( - 'establishment', - 'type', - ) + filter_class = filters.PartnerFilterSet class PartnerRUDView(generics.RetrieveUpdateDestroyAPIView): From 8be85707c7c2c166de88228e96e1ed0916b6e3be Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 14:15:01 +0300 Subject: [PATCH 019/101] fix published news --- apps/news/models.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/news/models.py b/apps/news/models.py index 2316fc27..3a529cc4 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -128,8 +128,14 @@ class NewsQuerySet(TranslationQuerysetMixin): return self.exclude(models.Q(publication_date__isnull=True) | models.Q(publication_time__isnull=True)). \ filter(models.Q(models.Q(end__gte=now) | models.Q(end__isnull=True)), - state__in=self.model.PUBLISHED_STATES, publication_date__lte=date_now, - publication_time__lte=time_now) + state__in=self.model.PUBLISHED_STATES)\ + .annotate(visible_now=Case( + When(publication_date__gt=date_now, then=False), + When(Q(publication_date=date_now) & Q(publication_time__gt=time_now), then=False), + default=True, + output_field=models.BooleanField() + ))\ + .exclude(visible_now=False) # todo: filter by best score # todo: filter by country? From 21006e77cb753fd19cb0cbc605d6ebde7854d687 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 15:16:29 +0300 Subject: [PATCH 020/101] user id in self info --- apps/account/serializers/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/account/serializers/common.py b/apps/account/serializers/common.py index 6722e539..c44170d4 100644 --- a/apps/account/serializers/common.py +++ b/apps/account/serializers/common.py @@ -87,6 +87,7 @@ class UserSerializer(serializers.ModelSerializer): class Meta: model = models.User fields = [ + 'id', 'username', 'first_name', 'last_name', From bf60479c66fcabbbf2e560cad00928cf8c1cd0de Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 15:38:06 +0300 Subject: [PATCH 021/101] user short name serializer added username --- apps/account/serializers/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/account/serializers/common.py b/apps/account/serializers/common.py index c44170d4..a537c1bf 100644 --- a/apps/account/serializers/common.py +++ b/apps/account/serializers/common.py @@ -191,6 +191,7 @@ class UserShortSerializer(UserSerializer): 'id', 'fullname', 'email', + 'username', ] From a8630661d89b0a6a2120c91717137d47cf4c002d Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 17:30:09 +0300 Subject: [PATCH 022/101] fix state --- apps/news/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 76b55ae6..f820fc29 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -237,7 +237,7 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer): 'duplication_date': {'read_only': True}, 'locale_to_description_is_active': {'allow_null': False}, 'must_of_the_week': {'read_only': True}, - 'state': {'read_only': True}, + # 'state': {'read_only': True}, 'state_display': {'read_only': True}, } From b6bfc51aadf48e72ed1371f7f2c2bb6ee30267fe Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 18:30:25 +0300 Subject: [PATCH 023/101] fix issue w/ news update --- apps/news/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index f820fc29..f88c79f0 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -304,7 +304,7 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer): slugs_set = set(slugs_list) if models.News.objects.filter( slugs__values__contains=list(slugs.values()) - ).exists() or len(slugs_list) != len(slugs_set): + ).exclude(pk=instance.pk).exists() or len(slugs_list) != len(slugs_set): raise serializers.ValidationError({'slugs': _('Slug should be unique')}) agenda_data = validated_data.get('agenda') From f5da5f71a310f1006879f179560a343f4cbac77d Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 18:45:23 +0300 Subject: [PATCH 024/101] base related qs for cities --- apps/establishment/views/back.py | 2 +- apps/location/models.py | 3 +++ apps/location/views/back.py | 2 +- apps/location/views/common.py | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 723d3844..62163ba3 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -353,7 +353,7 @@ class EstablishmentNoteListCreateView(EstablishmentMixinViews, lookup_field = 'slug' serializer_class = serializers.EstablishmentNoteListCreateSerializer - + permission_classes = (permissions.AllowAny, ) def get_object(self): """Returns the object the view is displaying.""" establishment_qs = models.Establishment.objects.all() diff --git a/apps/location/models.py b/apps/location/models.py index 97c02dd7..a8f4c43a 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -139,6 +139,9 @@ class CityQuerySet(models.QuerySet): """Return establishments by country code""" return self.filter(country__code=code) + def with_base_related(self): + return self.prefetch_related('country', 'region', 'region__country') + class City(models.Model): """Region model.""" diff --git a/apps/location/views/back.py b/apps/location/views/back.py index a0d1bd36..1e1957fe 100644 --- a/apps/location/views/back.py +++ b/apps/location/views/back.py @@ -44,7 +44,7 @@ class CityListCreateView(common.CityViewMixin, generics.ListCreateAPIView): def get_queryset(self): """Overridden method 'get_queryset'.""" qs = models.City.objects.all().annotate(locale_name=KeyTextTransform(get_current_locale(), 'name_translated'))\ - .order_by('locale_name') + .order_by('locale_name').with_base_related() if self.request.country_code: qs = qs.by_country_code(self.request.country_code) return qs diff --git a/apps/location/views/common.py b/apps/location/views/common.py index d9968755..475288fe 100644 --- a/apps/location/views/common.py +++ b/apps/location/views/common.py @@ -24,7 +24,7 @@ class RegionViewMixin(generics.GenericAPIView): class CityViewMixin(generics.GenericAPIView): """View Mixin for model City""" model = models.City - queryset = models.City.objects.all() + queryset = models.City.objects.with_base_related() class AddressViewMixin(generics.GenericAPIView): @@ -101,7 +101,7 @@ class CityListView(CityViewMixin, generics.ListAPIView): def get_queryset(self): qs = super().get_queryset() if self.request.country_code: - qs = qs.by_country_code(self.request.country_code) + qs = qs.by_country_code(self.request.country_code).with_base_related() return qs From 8a1651bf1feb2c2e55b618e987372881ceed60e3 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 18:45:50 +0300 Subject: [PATCH 025/101] fix permission --- apps/establishment/views/back.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 62163ba3..723d3844 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -353,7 +353,7 @@ class EstablishmentNoteListCreateView(EstablishmentMixinViews, lookup_field = 'slug' serializer_class = serializers.EstablishmentNoteListCreateSerializer - permission_classes = (permissions.AllowAny, ) + def get_object(self): """Returns the object the view is displaying.""" establishment_qs = models.Establishment.objects.all() From 205e2fa996414f17d641ca2a016c442b85f9c256 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 19:19:54 +0300 Subject: [PATCH 026/101] optimize collections --- apps/collection/models.py | 2 +- apps/collection/views/back.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/collection/models.py b/apps/collection/models.py index 8024effb..91173ed0 100644 --- a/apps/collection/models.py +++ b/apps/collection/models.py @@ -110,7 +110,7 @@ class Collection(ProjectBaseMixin, CollectionDateMixin, """Return list of related objects.""" related_objects = [] # get related objects - for related_object in self._meta.related_objects: + for related_object in self._meta.related_objects.with_base_related(): related_objects.append(related_object) return related_objects diff --git a/apps/collection/views/back.py b/apps/collection/views/back.py index 032bafb3..73fb7b18 100644 --- a/apps/collection/views/back.py +++ b/apps/collection/views/back.py @@ -21,7 +21,7 @@ class CollectionViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): def get_queryset(self): """Overridden method 'get_queryset'.""" - qs = models.Collection.objects.all().order_by('-created') + qs = models.Collection.objects.all().order_by('-created').with_base_related() if self.request.country_code: qs = qs.by_country_code(self.request.country_code) return qs From 7a6655930750180dac3b261f9f8ff81521f4886a Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 19:38:47 +0300 Subject: [PATCH 027/101] remove obviously unnecessary field --- .../0012_remove_subscribe_subscribe_date.py | 17 +++++++++++++++++ apps/notification/models.py | 5 ++++- apps/notification/serializers/common.py | 3 +++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 apps/notification/migrations/0012_remove_subscribe_subscribe_date.py diff --git a/apps/notification/migrations/0012_remove_subscribe_subscribe_date.py b/apps/notification/migrations/0012_remove_subscribe_subscribe_date.py new file mode 100644 index 00000000..cc805e4b --- /dev/null +++ b/apps/notification/migrations/0012_remove_subscribe_subscribe_date.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.7 on 2020-01-27 16:37 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('notification', '0011_auto_20200124_1351'), + ] + + operations = [ + migrations.RemoveField( + model_name='subscribe', + name='subscribe_date', + ), + ] diff --git a/apps/notification/models.py b/apps/notification/models.py index 094fcad4..a176034e 100644 --- a/apps/notification/models.py +++ b/apps/notification/models.py @@ -187,7 +187,6 @@ class SubscribeQuerySet(models.QuerySet): class Subscribe(ProjectBaseMixin): """Subscribe model.""" - subscribe_date = models.DateTimeField(_('Last subscribe date'), default=now(), blank=True, null=True) unsubscribe_date = models.DateTimeField(_('Last unsubscribe date'), blank=True, null=True, default=None) subscriber = models.ForeignKey(Subscriber, on_delete=models.CASCADE, null=True) @@ -198,6 +197,10 @@ class Subscribe(ProjectBaseMixin): objects = SubscribeQuerySet.as_manager() + @property + def subscribe_date(self): + return self.created + class Meta: """Meta class.""" diff --git a/apps/notification/serializers/common.py b/apps/notification/serializers/common.py index 6d5e9beb..282a763c 100644 --- a/apps/notification/serializers/common.py +++ b/apps/notification/serializers/common.py @@ -163,6 +163,9 @@ class SubscribeObjectSerializer(serializers.ModelSerializer): 'unsubscribe_date', 'subscription_type' ) + extra_kwargs = { + 'subscribe_date': {'read_only': True}, + } def get_subscription_type(self, instance): return SubscriptionTypeSerializer( From b9ee22c4a57bdcf9677083627797e6ffe767ae44 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 19:44:07 +0300 Subject: [PATCH 028/101] filter by states news --- apps/news/filters.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/news/filters.py b/apps/news/filters.py index 064f7175..7e2068a4 100644 --- a/apps/news/filters.py +++ b/apps/news/filters.py @@ -24,6 +24,8 @@ class NewsListFilterSet(filters.FilterSet): state = filters.NumberFilter() + state__in = filters.CharFilter(method='by_states_list') + SORT_BY_CREATED_CHOICE = "created" SORT_BY_START_CHOICE = "start" SORT_BY_CHOICES = ( @@ -54,6 +56,10 @@ class NewsListFilterSet(filters.FilterSet): return queryset.es_search(value, relevance_order='ordering' not in self.request.query_params) return queryset + def by_states_list(self, queryset, name, value): + states = value.splite('__') + return self.filters(state__in=states) + def in_tags(self, queryset, name, value): tags = value.split('__') return queryset.filter(tags__value__in=tags) From 9b6c70cf746cd6af2f227a1cd2aa5df06d45a201 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 19:45:04 +0300 Subject: [PATCH 029/101] fix typo --- apps/news/filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/news/filters.py b/apps/news/filters.py index 7e2068a4..6ead63f7 100644 --- a/apps/news/filters.py +++ b/apps/news/filters.py @@ -57,7 +57,7 @@ class NewsListFilterSet(filters.FilterSet): return queryset def by_states_list(self, queryset, name, value): - states = value.splite('__') + states = value.split('__') return self.filters(state__in=states) def in_tags(self, queryset, name, value): From 42d21a79a40db9cc312772db2ab87eac94eb6c63 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 19:46:17 +0300 Subject: [PATCH 030/101] fix typo again =\ --- apps/news/filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/news/filters.py b/apps/news/filters.py index 6ead63f7..7a2e4382 100644 --- a/apps/news/filters.py +++ b/apps/news/filters.py @@ -58,7 +58,7 @@ class NewsListFilterSet(filters.FilterSet): def by_states_list(self, queryset, name, value): states = value.split('__') - return self.filters(state__in=states) + return queryset.filter(state__in=states) def in_tags(self, queryset, name, value): tags = value.split('__') From 3796a698d2125305ff8faf73561ef6a2668b04cb Mon Sep 17 00:00:00 2001 From: dormantman Date: Mon, 27 Jan 2020 20:01:44 +0300 Subject: [PATCH 031/101] Added employee-establishment-positions method --- apps/establishment/urls/back.py | 4 +++- apps/establishment/views/back.py | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index 4769e332..396fa9d7 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -57,8 +57,10 @@ urlpatterns = [ path('subtypes/', views.EstablishmentSubtypeListCreateView.as_view(), name='subtype-list'), path('subtypes//', views.EstablishmentSubtypeRUDView.as_view(), name='subtype-rud'), path('positions/', views.EstablishmentPositionListView.as_view(), name='position-list'), - path('employee_positions//', views.EmployeePositionsListView.as_view(), + path('employee_positions//', views.EmployeePositionsListView.as_view(), name='employee-positions-list'), path('employee_establishments//', views.EmployeeEstablishmentsListView.as_view(), name='employee-establishments-list'), + path('employee_establishment_positions//', views.EmployeeEstablishmentPositionsListView.as_view(), + name='employee-establishment-positions-list') ] diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index eef93e18..4ba795a6 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -9,7 +9,6 @@ from rest_framework.response import Response from account.models import User from establishment import filters, models, serializers from establishment.models import EstablishmentEmployee -from establishment.serializers import PositionBackSerializer from timetable.models import Timetable from timetable.serialziers import ScheduleCreateSerializer, ScheduleRUDSerializer from utils.permissions import IsCountryAdmin, IsEstablishmentManager, IsWineryReviewer @@ -34,7 +33,7 @@ class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAP serializer_class = serializers.EstablishmentListCreateSerializer -class EmployeeEstablishmentsListView(generics.ListAPIView): +class EmployeeEstablishmentPositionsListView(generics.ListAPIView): """Establishment by employee list view.""" permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager] @@ -64,6 +63,19 @@ class EmployeeEstablishmentsListView(generics.ListAPIView): return Response(data) +class EmployeeEstablishmentsListView(generics.ListAPIView): + """Establishment by employee list view.""" + + permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager] + queryset = models.Establishment.objects.all() + serializer_class = serializers.EstablishmentListCreateSerializer + + def get_queryset(self): + pk = self.kwargs.get('pk') + employee = get_object_or_404(models.Employee, pk=pk) + return employee.establishments.with_extended_related() + + class EmployeePositionsListView(generics.ListAPIView): """Establishment position by employee list view.""" From f45eae56e9fe20ea780f9e020b6e7c3443cfcae2 Mon Sep 17 00:00:00 2001 From: dormantman Date: Mon, 27 Jan 2020 20:03:42 +0300 Subject: [PATCH 032/101] Added new features --- apps/establishment/serializers/back.py | 54 +++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 95b1050f..4729fe06 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -12,8 +12,9 @@ from location.models import Address from location.serializers import AddressDetailSerializer, TranslatedField from main.models import Currency from main.serializers import AwardSerializer +from timetable.serialziers import ScheduleRUDSerializer from utils.decorators import with_base_attributes -from utils.serializers import ImageBaseSerializer, TimeZoneChoiceField +from utils.serializers import ImageBaseSerializer, ProjectModelSerializer, TimeZoneChoiceField def phones_handler(phones_list, establishment): @@ -544,3 +545,54 @@ class EstablishmentEmployeeListSerializer(serializers.ModelSerializer): 'start', 'end', ] + + +class _PlateSerializer(ProjectModelSerializer): + name_translated = TranslatedField() + + class Meta: + model = models.Plate + fields = [ + 'name_translated', + 'price', + ] + + +class MenuDishesSerializer(ProjectModelSerializer): + """for dessert, main_course and starter category""" + + schedule = ScheduleRUDSerializer(many=True, allow_null=True) + plates = _PlateSerializer(read_only=True, many=True, source='plate_set', allow_null=True) + category_translated = serializers.CharField(read_only=True) + last_update = serializers.DateTimeField(source='created') + + class Meta: + model = models.Menu + fields = [ + 'id', + 'category', + 'category_translated', + 'establishment', + 'is_drinks_included', + 'schedule', + 'plates', + 'last_update', + ] + + +class MenuDishesRUDSerializers(ProjectModelSerializer): + """for dessert, main_course and starter category""" + + plates = _PlateSerializer(read_only=True, many=True, source='plate_set', allow_null=True) + schedule = ScheduleRUDSerializer(read_only=True, many=True, allow_null=True) + + class Meta: + model = models.Menu + fields = [ + 'id', + 'category', + 'plates', + 'establishment', + 'is_drinks_included', + 'schedule', + ] From e60f4b817b5d8edbb6138080915c189c8a3f9e04 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 20:04:36 +0300 Subject: [PATCH 033/101] API method for possible news states --- apps/news/serializers.py | 5 +++++ apps/news/urls/back.py | 1 + apps/news/views.py | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index f88c79f0..3103c4dd 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -508,3 +508,8 @@ class NewsCloneCreateSerializer(NewsBackOfficeBaseSerializer, view_count_model = rating_models.ViewCount.objects.create(count=0) instance.create_duplicate(new_country, view_count_model) return get_object_or_404(models.News, pk=kwargs['pk']) + + +class NewsStatesSerializer(serializers.Serializer): + value = serializers.IntegerField() + state_translated = serializers.CharField() diff --git a/apps/news/urls/back.py b/apps/news/urls/back.py index 54f40513..bf9ab856 100644 --- a/apps/news/urls/back.py +++ b/apps/news/urls/back.py @@ -8,6 +8,7 @@ app_name = 'news' urlpatterns = [ path('', views.NewsBackOfficeLCView.as_view(), name='list-create'), + path('states/', views.NewsStatesView.as_view(), name='possible-news-states-list'), path('/', views.NewsBackOfficeRUDView.as_view(), name='retrieve-update-destroy'), path('/gallery/', views.NewsBackOfficeGalleryListView.as_view(), name='gallery-list'), path('/gallery//', views.NewsBackOfficeGalleryCreateDestroyView.as_view(), diff --git a/apps/news/views.py b/apps/news/views.py index 4f0adc1e..948da401 100644 --- a/apps/news/views.py +++ b/apps/news/views.py @@ -51,6 +51,24 @@ class NewsMixinView: return instance +class NewsStatesView(generics.ListAPIView): + """Possible project news states""" + pagination_class = None + serializer_class = serializers.NewsStatesSerializer + + def get_queryset(self): + return None + + def list(self, request, *args, **kwargs): + mutated_for_serializer = [{ + 'value': state[0], + 'state_translated': state[1], + } for state in models.News.STATE_CHOICES] + print(mutated_for_serializer) + serializer = self.get_serializer(mutated_for_serializer, many=True) + return response.Response(serializer.data) + + class NewsListView(NewsMixinView, generics.ListAPIView): """News list view.""" From b687eb60248712b2b37c931c1260bed059cf7023 Mon Sep 17 00:00:00 2001 From: dormantman Date: Mon, 27 Jan 2020 20:29:42 +0300 Subject: [PATCH 034/101] Change format method --- apps/establishment/views/back.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 9f6e8b3e..239af07f 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -33,14 +33,14 @@ class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAP serializer_class = serializers.EstablishmentListCreateSerializer -class EmployeeEstablishmentPositionsListView(generics.ListAPIView): +class EmployeeEstablishmentPositionsListView(generics.GenericAPIView): """Establishment by employee list view.""" permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager] queryset = models.EstablishmentEmployee.objects.all() serializer_class = serializers.EstablishmentEmployeeListSerializer - def list(self, request, *args, **kwargs): + def get(self, request, *args, **kwargs): pk = self.kwargs.get('pk') employee = get_object_or_404(models.Employee, pk=pk) From e94787716eb37980d6ac1f3130466e5c0e2203b3 Mon Sep 17 00:00:00 2001 From: dormantman Date: Mon, 27 Jan 2020 20:33:51 +0300 Subject: [PATCH 035/101] Change labels --- apps/establishment/urls/back.py | 4 ++-- apps/establishment/views/back.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index 812ac6ea..556b5c8b 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -64,6 +64,6 @@ urlpatterns = [ name='employee-positions-list'), path('employee_establishments//', views.EmployeeEstablishmentsListView.as_view(), name='employee-establishments-list'), - path('employee_establishment_positions//', views.EmployeeEstablishmentPositionsListView.as_view(), - name='employee-establishment-positions-list') + path('employee_establishment_positions//', views.EmployeeEstablishmentPositionsView.as_view(), + name='employee-establishment-positions') ] diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 239af07f..4e8d102d 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -33,8 +33,8 @@ class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAP serializer_class = serializers.EstablishmentListCreateSerializer -class EmployeeEstablishmentPositionsListView(generics.GenericAPIView): - """Establishment by employee list view.""" +class EmployeeEstablishmentPositionsView(generics.GenericAPIView): + """Establishment by employee view.""" permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager] queryset = models.EstablishmentEmployee.objects.all() From 095e482358f0468398fe1db00dc0b55faed84621 Mon Sep 17 00:00:00 2001 From: dormantman Date: Mon, 27 Jan 2020 20:59:19 +0300 Subject: [PATCH 036/101] Optimize method --- apps/establishment/views/back.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 4e8d102d..2302f326 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -41,14 +41,12 @@ class EmployeeEstablishmentPositionsView(generics.GenericAPIView): serializer_class = serializers.EstablishmentEmployeeListSerializer def get(self, request, *args, **kwargs): - pk = self.kwargs.get('pk') - employee = get_object_or_404(models.Employee, pk=pk) + employee_pk = self.kwargs.get('pk') preload_data = defaultdict(list) - for establishment_employee in employee.establishmentemployee_set.all() \ + for establishment_employee in self.get_queryset().filter(employee__id=employee_pk).all() \ .prefetch_related('establishment').select_related('position'): establishment_name = establishment_employee.establishment.name - preload_data[establishment_name].append( serializers.EstablishmentEmployeeListSerializer(establishment_employee).data ) From 1fc0627ca9a678ea731d5db124deabc3eb9f43b2 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 21:10:26 +0300 Subject: [PATCH 037/101] email superuser --- apps/account/serializers/common.py | 37 +++++++++++++++++------------- apps/news/views.py | 1 - 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/apps/account/serializers/common.py b/apps/account/serializers/common.py index a537c1bf..2a67e5c1 100644 --- a/apps/account/serializers/common.py +++ b/apps/account/serializers/common.py @@ -139,22 +139,27 @@ class UserSerializer(serializers.ModelSerializer): new_email = validated_data.get('email') old_email = instance.email instance = super().update(instance, validated_data) - if new_email and new_email != old_email: - instance.email_confirmed = False - instance.email = old_email - instance.unconfirmed_email = new_email - instance.save() - # Send verification link on user email for change email address - if settings.USE_CELERY: - tasks.change_email_address.delay( - user_id=instance.id, - country_code=self.context.get('request').country_code, - emails=[validated_data['email'], ]) - else: - tasks.change_email_address( - user_id=instance.id, - country_code=self.context.get('request').country_code, - emails=[validated_data['email'], ]) + user = self.context['request'].user + if not user.is_superuser or not user.is_staff: + """ + superuser changes email immediately! + """ + if new_email and new_email != old_email: + instance.email_confirmed = False + instance.email = old_email + instance.unconfirmed_email = new_email + instance.save() + # Send verification link on user email for change email address + if settings.USE_CELERY: + tasks.change_email_address.delay( + user_id=instance.id, + country_code=self.context.get('request').country_code, + emails=[validated_data['email'], ]) + else: + tasks.change_email_address( + user_id=instance.id, + country_code=self.context.get('request').country_code, + emails=[validated_data['email'], ]) subscriptions_handler(subscriptions_list, instance) return instance diff --git a/apps/news/views.py b/apps/news/views.py index 948da401..c98a3c18 100644 --- a/apps/news/views.py +++ b/apps/news/views.py @@ -64,7 +64,6 @@ class NewsStatesView(generics.ListAPIView): 'value': state[0], 'state_translated': state[1], } for state in models.News.STATE_CHOICES] - print(mutated_for_serializer) serializer = self.get_serializer(mutated_for_serializer, many=True) return response.Response(serializer.data) From 415c9b7851fda3e5b61d06d7bba317a4ce1ff742 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 21:18:48 +0300 Subject: [PATCH 038/101] fix --- apps/establishment/views/back.py | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 2302f326..5d8f7dd5 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -81,21 +81,10 @@ class EmployeePositionsListView(generics.ListAPIView): queryset = models.Establishment.objects.all() serializer_class = serializers.EstablishmentPositionListSerializer - def list(self, request, *args, **kwargs): + def get_queryset(self): pk = self.kwargs.get('pk') employee = get_object_or_404(models.Employee, pk=pk) - - queryset = employee.establishments.with_extended_related() - queryset = self.filter_queryset(queryset) - - page = self.paginate_queryset(queryset) - if page is not None: - serializer = self.get_serializer(page, many=True) - return self.get_paginated_response(serializer.data) - - serializer = self.get_serializer(queryset, many=True) - - return Response(serializer.data) + return employee.establishments.with_extended_related() class EstablishmentRUDView(generics.RetrieveUpdateDestroyAPIView): From d51d3040776066aea8c5437b06d4fb30d392d2a6 Mon Sep 17 00:00:00 2001 From: dormantman Date: Mon, 27 Jan 2020 21:45:06 +0300 Subject: [PATCH 039/101] Refactor (structure) --- apps/establishment/serializers/back.py | 6 ++++-- apps/establishment/views/back.py | 23 ++++++----------------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 6eb4b40d..c9b2f2fe 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -14,7 +14,7 @@ from main.models import Currency from main.serializers import AwardSerializer from timetable.serialziers import ScheduleRUDSerializer from utils.decorators import with_base_attributes -from utils.serializers import ImageBaseSerializer, TimeZoneChoiceField, ProjectModelSerializer +from utils.serializers import ImageBaseSerializer, ProjectModelSerializer, TimeZoneChoiceField def phones_handler(phones_list, establishment): @@ -529,9 +529,10 @@ class EstablishmentAdminListSerializer(UserShortSerializer): ] -class EstablishmentEmployeeListSerializer(serializers.ModelSerializer): +class EstablishmentEmployeePositionsSerializer(serializers.ModelSerializer): """Establishments from employee serializer""" + restaurant_name = serializers.CharField(read_only=True, source='establishment.name') position = PositionBackSerializer(read_only=True) state = serializers.CharField(read_only=True, source='status') start = serializers.DateTimeField(read_only=True, source='from_date') @@ -540,6 +541,7 @@ class EstablishmentEmployeeListSerializer(serializers.ModelSerializer): class Meta: model = models.EstablishmentEmployee fields = [ + 'restaurant_name', 'position', 'state', 'start', diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 5d8f7dd5..abe89404 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -38,27 +38,16 @@ class EmployeeEstablishmentPositionsView(generics.GenericAPIView): permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager] queryset = models.EstablishmentEmployee.objects.all() - serializer_class = serializers.EstablishmentEmployeeListSerializer + serializer_class = serializers.EstablishmentEmployeePositionsSerializer def get(self, request, *args, **kwargs): employee_pk = self.kwargs.get('pk') - preload_data = defaultdict(list) - for establishment_employee in self.get_queryset().filter(employee__id=employee_pk).all() \ - .prefetch_related('establishment').select_related('position'): - establishment_name = establishment_employee.establishment.name - preload_data[establishment_name].append( - serializers.EstablishmentEmployeeListSerializer(establishment_employee).data - ) - - data = [{ - 'restaurant_name': establishment_name, - 'positions': [ - preload_data[establishment_name] - ] - } for establishment_name in preload_data] - - return Response(data) + return Response(self.get_serializer( + self.get_queryset().filter(employee__id=employee_pk).all() + .prefetch_related('establishment').select_related('position'), + many=True + ).data) class EmployeeEstablishmentsListView(generics.ListAPIView): From 4cfe613739056485dcaae598d8b1bce6377a627d Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 21:47:04 +0300 Subject: [PATCH 040/101] roles for email changing --- apps/account/serializers/common.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/account/serializers/common.py b/apps/account/serializers/common.py index 2a67e5c1..30923909 100644 --- a/apps/account/serializers/common.py +++ b/apps/account/serializers/common.py @@ -139,10 +139,12 @@ class UserSerializer(serializers.ModelSerializer): new_email = validated_data.get('email') old_email = instance.email instance = super().update(instance, validated_data) - user = self.context['request'].user - if not user.is_superuser or not user.is_staff: + request = self.context['request'] + user = request.user + if not user.is_superuser or not user.is_staff or \ + not user.roles.filter(country__code=request.country_code, role=models.Role.COUNTRY_ADMIN).exists(): """ - superuser changes email immediately! + superuser or country admin changes email immediately! """ if new_email and new_email != old_email: instance.email_confirmed = False From 4b0ef25baff0c55ccbcc91645ec3e5e1af9add52 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 21:53:18 +0300 Subject: [PATCH 041/101] roles for email changing #2 --- apps/account/serializers/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/account/serializers/common.py b/apps/account/serializers/common.py index 30923909..197c3a84 100644 --- a/apps/account/serializers/common.py +++ b/apps/account/serializers/common.py @@ -141,7 +141,7 @@ class UserSerializer(serializers.ModelSerializer): instance = super().update(instance, validated_data) request = self.context['request'] user = request.user - if not user.is_superuser or not user.is_staff or \ + if not user.is_superuser and not user.is_staff and \ not user.roles.filter(country__code=request.country_code, role=models.Role.COUNTRY_ADMIN).exists(): """ superuser or country admin changes email immediately! From bb38bb3393ea902ebda94b6be38a862818ed6855 Mon Sep 17 00:00:00 2001 From: dormantman Date: Mon, 27 Jan 2020 22:22:17 +0300 Subject: [PATCH 042/101] Change api view method --- apps/establishment/views/back.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index abe89404..1dc7f6d9 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -1,5 +1,4 @@ """Establishment app views.""" -from collections import defaultdict from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend @@ -33,21 +32,17 @@ class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAP serializer_class = serializers.EstablishmentListCreateSerializer -class EmployeeEstablishmentPositionsView(generics.GenericAPIView): +class EmployeeEstablishmentPositionsView(generics.ListAPIView): """Establishment by employee view.""" permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager] queryset = models.EstablishmentEmployee.objects.all() serializer_class = serializers.EstablishmentEmployeePositionsSerializer - def get(self, request, *args, **kwargs): + def get_queryset(self): employee_pk = self.kwargs.get('pk') - - return Response(self.get_serializer( - self.get_queryset().filter(employee__id=employee_pk).all() - .prefetch_related('establishment').select_related('position'), - many=True - ).data) + return super().get_queryset().filter(employee__id=employee_pk).all().prefetch_related( + 'establishment').select_related('position') class EmployeeEstablishmentsListView(generics.ListAPIView): From 468527bc0e9388f29b865327086ab5ba65e3722e Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 23:13:14 +0300 Subject: [PATCH 043/101] localized cities #1 --- .../migrations/0036_auto_20200127_2004.py | 41 +++++++++++++++++++ apps/location/models.py | 4 +- apps/search_indexes/signals.py | 2 +- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 apps/location/migrations/0036_auto_20200127_2004.py diff --git a/apps/location/migrations/0036_auto_20200127_2004.py b/apps/location/migrations/0036_auto_20200127_2004.py new file mode 100644 index 00000000..af475a6a --- /dev/null +++ b/apps/location/migrations/0036_auto_20200127_2004.py @@ -0,0 +1,41 @@ +# Generated by Django 2.2.7 on 2020-01-27 20:04 + +from django.db import migrations, models +import utils.models + + +def clear_data(apps, schema_editor): + City = apps.get_model('location', 'City') + for city in City.objects.all(): + city.name = None + city.save() + + +def preserve_field_data(apps, schema_editor): + City = apps.get_model('location', 'City') + for city in City.objects.all(): + city.name = city.name_translated + city.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('location', '0035_auto_20200115_1117'), + ] + + + operations = [ + migrations.AlterField( + model_name='city', + name='name', + field=models.CharField(max_length=250, null=True, verbose_name='name'), + ), + migrations.RunPython(clear_data, migrations.RunPython.noop), + migrations.AlterField( + model_name='city', + name='name', + field=utils.models.TJSONField(default=None, help_text='{"en-GB":"some city name"}', null=True, verbose_name='City name json'), + ), + migrations.RunPython(preserve_field_data, migrations.RunPython.noop), + ] diff --git a/apps/location/models.py b/apps/location/models.py index a8f4c43a..36eb575a 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -145,7 +145,9 @@ class CityQuerySet(models.QuerySet): class City(models.Model): """Region model.""" - name = models.CharField(_('name'), max_length=250) + name = TJSONField(default=None, null=True, help_text='{"en-GB":"some city name"}', + verbose_name=_('City name json')) + name_translated = TJSONField(blank=True, null=True, default=None, verbose_name=_('Translated name'), help_text='{"en-GB":"some text"}') diff --git a/apps/search_indexes/signals.py b/apps/search_indexes/signals.py index 0a6fb4f6..0f89139a 100644 --- a/apps/search_indexes/signals.py +++ b/apps/search_indexes/signals.py @@ -13,7 +13,7 @@ def update_document(sender, **kwargs): app_label_model_name_to_filter = { ('location', 'country'): 'address__city__country', - ('location', 'city'): 'address__city', + # ('location', 'city'): 'address__city', ('location', 'address'): 'address', # todo: remove after migration ('establishment', 'establishmenttype'): 'establishment_type', From ff34d66854f594f63949f5cac7a7594ced98a741 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 23:15:48 +0300 Subject: [PATCH 044/101] localized cities #2 --- apps/location/migrations/0036_auto_20200127_2004.py | 4 ++++ apps/location/models.py | 6 +----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/location/migrations/0036_auto_20200127_2004.py b/apps/location/migrations/0036_auto_20200127_2004.py index af475a6a..4dcb5132 100644 --- a/apps/location/migrations/0036_auto_20200127_2004.py +++ b/apps/location/migrations/0036_auto_20200127_2004.py @@ -38,4 +38,8 @@ class Migration(migrations.Migration): field=utils.models.TJSONField(default=None, help_text='{"en-GB":"some city name"}', null=True, verbose_name='City name json'), ), migrations.RunPython(preserve_field_data, migrations.RunPython.noop), + migrations.RemoveField( + model_name='city', + name='name_translated', + ) ] diff --git a/apps/location/models.py b/apps/location/models.py index 36eb575a..ed12ad4f 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -143,14 +143,10 @@ class CityQuerySet(models.QuerySet): return self.prefetch_related('country', 'region', 'region__country') -class City(models.Model): +class City(models.Model, TranslatedFieldsMixin): """Region model.""" name = TJSONField(default=None, null=True, help_text='{"en-GB":"some city name"}', verbose_name=_('City name json')) - - name_translated = TJSONField(blank=True, null=True, default=None, - verbose_name=_('Translated name'), - help_text='{"en-GB":"some text"}') code = models.CharField(_('code'), max_length=250) region = models.ForeignKey(Region, on_delete=models.CASCADE, blank=True, null=True, From e1b2c74988dd8c30abb9cf8aaa5082dadfda988e Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 23:19:25 +0300 Subject: [PATCH 045/101] localized cities #3 --- apps/location/serializers/back.py | 5 +++++ apps/location/serializers/common.py | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/location/serializers/back.py b/apps/location/serializers/back.py index c178f7fd..4f2b1ea8 100644 --- a/apps/location/serializers/back.py +++ b/apps/location/serializers/back.py @@ -1,6 +1,8 @@ from location import models from location.serializers import common +from utils.serializers import TranslatedField + class AddressCreateSerializer(common.AddressDetailSerializer): """Address create serializer.""" @@ -9,6 +11,8 @@ class AddressCreateSerializer(common.AddressDetailSerializer): class CountryBackSerializer(common.CountrySerializer): """Country back-office serializer.""" + name_translated = TranslatedField() + class Meta: model = models.Country fields = [ @@ -16,5 +20,6 @@ class CountryBackSerializer(common.CountrySerializer): 'code', 'svg_image', 'name', + 'name_translated', 'country_id' ] diff --git a/apps/location/serializers/common.py b/apps/location/serializers/common.py index 1da144f8..8b44f440 100644 --- a/apps/location/serializers/common.py +++ b/apps/location/serializers/common.py @@ -59,13 +59,14 @@ class RegionSerializer(serializers.ModelSerializer): class CityShortSerializer(serializers.ModelSerializer): """Short city serializer""" country = CountrySerializer(read_only=True) + name_translated = TranslatedField() class Meta: """Meta class""" model = models.City fields = ( 'id', - 'name', + 'name_translated', 'code', 'country', ) @@ -91,12 +92,14 @@ class CityBaseSerializer(serializers.ModelSerializer): required=False, ) country = CountrySerializer(read_only=True) + name_translated = TranslatedField() class Meta: model = models.City fields = [ 'id', 'name', + 'name_translated', 'region', 'region_id', 'country_id', From faeec9b4f2d1698c45aa8f6062a90a748573ca06 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 23:22:53 +0300 Subject: [PATCH 046/101] localized cities #4 --- apps/location/views/back.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/location/views/back.py b/apps/location/views/back.py index 1e1957fe..98556e86 100644 --- a/apps/location/views/back.py +++ b/apps/location/views/back.py @@ -55,7 +55,7 @@ class CityListSearchView(common.CityViewMixin, generics.ListCreateAPIView): serializer_class = serializers.CityBaseSerializer permission_classes = [IsAuthenticatedOrReadOnly | IsCountryAdmin] queryset = models.City.objects.all()\ - .annotate(locale_name=KeyTextTransform(get_current_locale(), 'name_translated'))\ + .annotate(locale_name=KeyTextTransform(get_current_locale(), 'name'))\ .order_by('locale_name') filter_class = filters.CityBackFilter pagination_class = None From 5c75b0a3accf07193e8d8d0b9b125d30f47d2465 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 23:24:01 +0300 Subject: [PATCH 047/101] localized cities #5 --- apps/location/views/back.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/location/views/back.py b/apps/location/views/back.py index 98556e86..ec8f914c 100644 --- a/apps/location/views/back.py +++ b/apps/location/views/back.py @@ -43,7 +43,7 @@ class CityListCreateView(common.CityViewMixin, generics.ListCreateAPIView): def get_queryset(self): """Overridden method 'get_queryset'.""" - qs = models.City.objects.all().annotate(locale_name=KeyTextTransform(get_current_locale(), 'name_translated'))\ + qs = models.City.objects.all().annotate(locale_name=KeyTextTransform(get_current_locale(), 'name'))\ .order_by('locale_name').with_base_related() if self.request.country_code: qs = qs.by_country_code(self.request.country_code) From 781779d54a48f2d1c7021d45982e3b1761335ae4 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 27 Jan 2020 23:30:17 +0300 Subject: [PATCH 048/101] localized cities #6 --- apps/search_indexes/documents/establishment.py | 2 +- apps/search_indexes/documents/product.py | 2 +- apps/search_indexes/serializers.py | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/search_indexes/documents/establishment.py b/apps/search_indexes/documents/establishment.py index 0b221102..d079036d 100644 --- a/apps/search_indexes/documents/establishment.py +++ b/apps/search_indexes/documents/establishment.py @@ -175,7 +175,7 @@ class EstablishmentDocument(Document): 'city': fields.ObjectField( properties={ 'id': fields.IntegerField(), - 'name': fields.KeywordField(), + 'name_translated': fields.KeywordField(), 'is_island': fields.BooleanField(), 'country': fields.ObjectField( properties={ diff --git a/apps/search_indexes/documents/product.py b/apps/search_indexes/documents/product.py index fda06492..3db6adec 100644 --- a/apps/search_indexes/documents/product.py +++ b/apps/search_indexes/documents/product.py @@ -44,7 +44,7 @@ class ProductDocument(Document): attr='address.city', properties={ 'id': fields.IntegerField(), - 'name': fields.KeywordField(), + 'name_translated': fields.KeywordField(), 'code': fields.KeywordField(), 'country': fields.ObjectField( properties={ diff --git a/apps/search_indexes/serializers.py b/apps/search_indexes/serializers.py index b909fb1b..8c4b9396 100644 --- a/apps/search_indexes/serializers.py +++ b/apps/search_indexes/serializers.py @@ -124,7 +124,8 @@ class CityDocumentShortSerializer(serializers.Serializer): id = serializers.IntegerField() code = serializers.CharField(allow_null=True) - name = serializers.CharField() + # todo: index and use name dict field + name_translated = serializers.CharField() class CountryDocumentSerializer(serializers.Serializer): From c0f3aca5324ea8d3e27e23a2a08ebff4dca16799 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 28 Jan 2020 12:16:56 +0300 Subject: [PATCH 049/101] menu gallery --- .../migrations/0080_auto_20200128_0904.py | 40 +++++++++++++++++++ .../migrations/0081_menuuploads_title.py | 18 +++++++++ apps/establishment/models.py | 40 +++++++++++++++++-- apps/establishment/serializers/back.py | 10 ++++- 4 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 apps/establishment/migrations/0080_auto_20200128_0904.py create mode 100644 apps/establishment/migrations/0081_menuuploads_title.py diff --git a/apps/establishment/migrations/0080_auto_20200128_0904.py b/apps/establishment/migrations/0080_auto_20200128_0904.py new file mode 100644 index 00000000..e111fad5 --- /dev/null +++ b/apps/establishment/migrations/0080_auto_20200128_0904.py @@ -0,0 +1,40 @@ +# Generated by Django 2.2.7 on 2020-01-28 09:04 + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('gallery', '0008_merge_20191212_0752'), + ('establishment', '0079_auto_20200124_0720'), + ] + + operations = [ + migrations.AlterField( + model_name='menuuploads', + name='file', + field=models.FileField(upload_to='', validators=[django.core.validators.FileExtensionValidator(allowed_extensions=('doc', 'docx', 'pdf'))], verbose_name='File'), + ), + migrations.AlterField( + model_name='menuuploads', + name='menu', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='menu_uploads', to='establishment.Menu', verbose_name='menu'), + ), + migrations.CreateModel( + name='MenuGallery', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('is_main', models.BooleanField(default=False, verbose_name='Is the main image')), + ('image', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='menu_gallery', to='gallery.Image', verbose_name='image')), + ('menu', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='menu_gallery', to='establishment.Menu', verbose_name='menu')), + ], + options={ + 'verbose_name': 'menu gallery', + 'verbose_name_plural': 'menu galleries', + 'unique_together': {('menu', 'image'), ('menu', 'is_main')}, + }, + ), + ] diff --git a/apps/establishment/migrations/0081_menuuploads_title.py b/apps/establishment/migrations/0081_menuuploads_title.py new file mode 100644 index 00000000..820bdcb2 --- /dev/null +++ b/apps/establishment/migrations/0081_menuuploads_title.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.7 on 2020-01-28 09:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0080_auto_20200128_0904'), + ] + + operations = [ + migrations.AddField( + model_name='menuuploads', + name='title', + field=models.CharField(default='', max_length=255, verbose_name='title'), + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 5f575c78..07c8465d 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -1238,6 +1238,11 @@ class MenuQuerySet(models.QuerySet): 'plates', ) + def with_gallery(self): + return self.prefetch_related( + 'menu_gallery' + ) + def dishes(self): return self.filter( Q(category__icontains='starter') | @@ -1250,7 +1255,7 @@ class MenuQuerySet(models.QuerySet): return self.filter(category__icontains=value) -class Menu(TranslatedFieldsMixin, BaseAttributes): +class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes): """Menu model.""" STR_FIELD_NAME = 'category' @@ -1278,13 +1283,42 @@ class Menu(TranslatedFieldsMixin, BaseAttributes): ordering = ('-created',) +class MenuGallery(IntermediateGalleryModelMixin): + menu = models.ForeignKey( + Menu, + null=True, + related_name='menu_gallery', + on_delete=models.CASCADE, + verbose_name=_('menu'), + ) + image = models.ForeignKey( + 'gallery.Image', + null=True, + related_name='menu_gallery', + on_delete=models.CASCADE, + verbose_name=_('image'), + ) + + class Meta: + """Meta class.""" + verbose_name = _('menu gallery') + verbose_name_plural = _('menu galleries') + unique_together = (('menu', 'is_main'), ('menu', 'image')) + + class MenuUploads(BaseAttributes): """Menu files""" - menu = models.ForeignKey(Menu, verbose_name=_('Menu'), on_delete=models.CASCADE, related_name='uploads') + menu = models.ForeignKey( + Menu, + verbose_name=_('menu'), + on_delete=models.CASCADE, + related_name='menu_uploads', + ) + title = models.CharField(_('title'), max_length=255, default='') file = models.FileField( _('File'), - validators=[FileExtensionValidator(allowed_extensions=('jpg', 'jpeg', 'png', 'doc', 'docx', 'pdf')), ], + validators=[FileExtensionValidator(allowed_extensions=('doc', 'docx', 'pdf')), ], ) class Meta: diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index c9b2f2fe..d9a78f3e 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -560,13 +560,19 @@ class _PlateSerializer(ProjectModelSerializer): ] +class _MenuUploadsSerializer(serializers.Serializer): + id = serializers.IntegerField() + title = serializers.CharField() + original_url = serializers.URLField() + + class MenuDishesSerializer(ProjectModelSerializer): """for dessert, main_course and starter category""" - schedule = ScheduleRUDSerializer(many=True, allow_null=True) plates = _PlateSerializer(read_only=True, many=True, source='plate_set', allow_null=True) category_translated = serializers.CharField(read_only=True) last_update = serializers.DateTimeField(source='created') + gallery = ImageBaseSerializer(read_only=True, source='crop_gallery', many=True) class Meta: model = models.Menu @@ -579,6 +585,7 @@ class MenuDishesSerializer(ProjectModelSerializer): 'schedule', 'plates', 'last_update', + 'gallery', ] @@ -586,7 +593,6 @@ class MenuDishesRUDSerializers(ProjectModelSerializer): """for dessert, main_course and starter category""" plates = _PlateSerializer(read_only=True, many=True, source='plate_set', allow_null=True) - schedule = ScheduleRUDSerializer(read_only=True, many=True, allow_null=True) class Meta: model = models.Menu From 029cd36b980c8391cd80df982617010558532dd8 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 12:35:23 +0300 Subject: [PATCH 050/101] localized cities #7 --- apps/location/models.py | 17 +++++++++++------ apps/search_indexes/documents/establishment.py | 1 + apps/search_indexes/documents/product.py | 1 + apps/search_indexes/serializers.py | 7 ++++++- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/location/models.py b/apps/location/models.py index ed12ad4f..5b2fa721 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -1,20 +1,20 @@ """Location app models.""" +from functools import reduce +from json import dumps +from typing import List + from django.conf import settings from django.contrib.gis.db import models +from django.contrib.postgres.fields import ArrayField from django.db.models.signals import post_save from django.db.transaction import on_commit from django.dispatch import receiver from django.utils.translation import gettext_lazy as _ -from functools import reduce -from typing import List -from django.contrib.postgres.fields.jsonb import KeyTextTransform - -from django.contrib.postgres.fields import ArrayField from translation.models import Language from utils.models import (ProjectBaseMixin, SVGImageMixin, TJSONField, TranslatedFieldsMixin, get_current_locale, - IntermediateGalleryModelMixin, GalleryMixin) + IntermediateGalleryModelMixin) class CountryQuerySet(models.QuerySet): @@ -180,6 +180,11 @@ class City(models.Model, TranslatedFieldsMixin): def __str__(self): return self.name + @property + def name_dumped(self): + """Used for indexing as string""" + return dumps(self.name) + @property def image_object(self): """Return image object.""" diff --git a/apps/search_indexes/documents/establishment.py b/apps/search_indexes/documents/establishment.py index d079036d..2a873e12 100644 --- a/apps/search_indexes/documents/establishment.py +++ b/apps/search_indexes/documents/establishment.py @@ -175,6 +175,7 @@ class EstablishmentDocument(Document): 'city': fields.ObjectField( properties={ 'id': fields.IntegerField(), + 'name': fields.KeywordField(attr='name_dumped'), 'name_translated': fields.KeywordField(), 'is_island': fields.BooleanField(), 'country': fields.ObjectField( diff --git a/apps/search_indexes/documents/product.py b/apps/search_indexes/documents/product.py index 3db6adec..a2bc377f 100644 --- a/apps/search_indexes/documents/product.py +++ b/apps/search_indexes/documents/product.py @@ -44,6 +44,7 @@ class ProductDocument(Document): attr='address.city', properties={ 'id': fields.IntegerField(), + 'name': fields.KeywordField(attr='name_dumped'), 'name_translated': fields.KeywordField(), 'code': fields.KeywordField(), 'country': fields.ObjectField( diff --git a/apps/search_indexes/serializers.py b/apps/search_indexes/serializers.py index 8c4b9396..549255db 100644 --- a/apps/search_indexes/serializers.py +++ b/apps/search_indexes/serializers.py @@ -125,7 +125,12 @@ class CityDocumentShortSerializer(serializers.Serializer): id = serializers.IntegerField() code = serializers.CharField(allow_null=True) # todo: index and use name dict field - name_translated = serializers.CharField() + name_translated = serializers.SerializerMethodField() + + @staticmethod + def get_name_translated(obj): + get_translated_value(loads(obj.name)) + class CountryDocumentSerializer(serializers.Serializer): From a02a52f2b038a81229a9fc8bc278864f675fa4fa Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 28 Jan 2020 12:49:45 +0300 Subject: [PATCH 051/101] menu dishes gallery api --- apps/establishment/serializers/back.py | 52 +++++++++++++++++++++++- apps/establishment/urls/back.py | 3 ++ apps/establishment/views/back.py | 55 +++++++++++++++++++++++++- 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index d9a78f3e..4b9744e9 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -12,7 +12,6 @@ from location.models import Address from location.serializers import AddressDetailSerializer, TranslatedField from main.models import Currency from main.serializers import AwardSerializer -from timetable.serialziers import ScheduleRUDSerializer from utils.decorators import with_base_attributes from utils.serializers import ImageBaseSerializer, ProjectModelSerializer, TimeZoneChoiceField @@ -593,6 +592,7 @@ class MenuDishesRUDSerializers(ProjectModelSerializer): """for dessert, main_course and starter category""" plates = _PlateSerializer(read_only=True, many=True, source='plate_set', allow_null=True) + gallery = ImageBaseSerializer(read_only=True, source='crop_gallery', many=True) class Meta: model = models.Menu @@ -603,4 +603,54 @@ class MenuDishesRUDSerializers(ProjectModelSerializer): 'establishment', 'is_drinks_included', 'schedule', + 'gallery', ] + + +class MenuGallerySerializer(serializers.ModelSerializer): + """Serializer class for model MenuGallery.""" + + class Meta: + """Meta class""" + + model = models.MenuGallery + fields = [ + 'id', + 'is_main', + ] + + @property + def request_kwargs(self): + """Get url kwargs from request.""" + return self.context.get('request').parser_context.get('kwargs') + + def create(self, validated_data): + menu_pk = self.request_kwargs.get('pk') + image_id = self.request_kwargs.get('image_id') + qs = models.MenuGallery.objects.filter(image_id=image_id, menu_id=menu_pk) + instance = qs.first() + if instance: + qs.update(**validated_data) + return instance + return super().create(validated_data) + + def validate(self, attrs): + """Override validate method.""" + menu_pk = self.request_kwargs.get('pk') + image_id = self.request_kwargs.get('image_id') + + menu_qs = models.Menu.objects.filter(pk=menu_pk) + image_qs = Image.objects.filter(id=image_id) + + if not menu_qs.exists(): + raise serializers.ValidationError({'detail': _('Menu not found')}) + if not image_qs.exists(): + raise serializers.ValidationError({'detail': _('Image not found')}) + + menu = menu_qs.first() + image = image_qs.first() + + attrs['menu'] = menu + attrs['image'] = image + + return attrs diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index 556b5c8b..d5173942 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -32,6 +32,9 @@ urlpatterns = [ name='establishment-admin-list'), path('menus/dishes/', views.MenuDishesListCreateView.as_view(), name='menu-dishes-list'), path('menus/dishes//', views.MenuDishesRUDView.as_view(), name='menu-dishes-rud'), + path('menus/dishes//gallery/', views.MenuGalleryListView.as_view(), name='menu-dishes-gallery-list'), + path('menus/dishes//gallery//', views.MenuGalleryCreateDestroyView.as_view(), + name='menu-dishes-gallery-create-destroy'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus//', views.MenuRUDView.as_view(), name='menu-rud'), path('plates/', views.PlateListCreateView.as_view(), name='plates'), diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 1dc7f6d9..dfd5ded7 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -2,7 +2,7 @@ from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend -from rest_framework import generics, permissions +from rest_framework import generics, permissions, response from rest_framework.response import Response from account.models import User @@ -462,3 +462,56 @@ class MenuDishesRUDView(generics.RetrieveUpdateDestroyAPIView): serializer_class = serializers.MenuDishesRUDSerializers queryset = models.Menu.objects.dishes().distinct() permission_classes = [IsWineryReviewer | IsEstablishmentManager] + + +class MenuGalleryListView(generics.ListAPIView): + """Resource for returning gallery for menu for back-office users.""" + serializer_class = serializers.ImageBaseSerializer + permission_classes = [IsWineryReviewer | IsEstablishmentManager] + queryset = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() + + def get_object(self): + """Override get_object method.""" + qs = super(MenuGalleryListView, self).get_queryset() + menu = get_object_or_404(qs, pk=self.kwargs.get('pk')) + + # May raise a permission denied + # self.check_object_permissions(self.request, menu) + + return menu + + def get_queryset(self): + """Override get_queryset method.""" + return self.get_object().crop_gallery + + +class MenuGalleryCreateDestroyView(CreateDestroyGalleryViewMixin): + """Resource for a create gallery for menu for back-office users.""" + serializer_class = serializers.MenuGallerySerializer + permission_classes = [IsWineryReviewer | IsEstablishmentManager] + + def get_queryset(self): + """Override get_queryset method.""" + qs = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() + return qs + + def create(self, request, *args, **kwargs): + _ = super().create(request, *args, **kwargs) + news_qs = self.filter_queryset(self.get_queryset()) + return response.Response( + data=serializers.MenuDishesRUDSerializers(get_object_or_404(news_qs, pk=kwargs.get('pk'))).data + ) + + def get_object(self): + """ + Returns the object the view is displaying. + """ + menu_qs = self.filter_queryset(self.get_queryset()) + + menu = get_object_or_404(menu_qs, pk=self.kwargs.get('pk')) + gallery = get_object_or_404(menu.menu_gallery, image_id=self.kwargs.get('image_id')) + + # May raise a permission denied + self.check_object_permissions(self.request, gallery) + + return gallery From cec7a583389cf2e1789befec5c8b2e3bda966fee Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 13:25:44 +0300 Subject: [PATCH 052/101] fix typo --- apps/search_indexes/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/search_indexes/serializers.py b/apps/search_indexes/serializers.py index 549255db..29144189 100644 --- a/apps/search_indexes/serializers.py +++ b/apps/search_indexes/serializers.py @@ -129,7 +129,7 @@ class CityDocumentShortSerializer(serializers.Serializer): @staticmethod def get_name_translated(obj): - get_translated_value(loads(obj.name)) + return get_translated_value(loads(obj.name)) From 193f1655e4cdd03742ddd2b72e7b378389e35d58 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 28 Jan 2020 14:36:54 +0300 Subject: [PATCH 053/101] email cascade establishment --- apps/establishment/models.py | 8 ++++++ apps/establishment/serializers/back.py | 40 ++++++++++++++++++++++---- apps/establishment/views/back.py | 2 +- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 07c8465d..fbe333cf 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -514,6 +514,9 @@ class EstablishmentQuerySet(models.QuerySet): to_attr='main_image') ) + def with_contacts(self): + return self.prefetch_related('emails', 'phones') + class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin, HasTagsMixin, FavoritesMixin): @@ -817,6 +820,11 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, if self.phones: return [phone.phone.as_e164 for phone in self.phones.all()] + @property + def contact_emails(self): + if self.phones: + return [email.email for email in self.emails.all()] + @property def establishment_subtype_labels(self): if self.establishment_subtypes: diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 4b9744e9..cf463454 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -6,7 +6,7 @@ from rest_framework import serializers from account.serializers.common import UserShortSerializer from establishment import models, serializers as model_serializers -from establishment.models import ContactPhone, EstablishmentEmployee +from establishment.models import ContactPhone, EstablishmentEmployee, ContactEmail from gallery.models import Image from location.models import Address from location.serializers import AddressDetailSerializer, TranslatedField @@ -26,6 +26,16 @@ def phones_handler(phones_list, establishment): ContactPhone.objects.create(establishment=establishment, phone=new_phone) +def emails_handler(emails_list, establishment): + """ + create or update emails for establishment + """ + ContactEmail.objects.filter(establishment=establishment).delete() + + for new_email in emails_list: + ContactEmail.objects.create(establishment=establishment, email=new_email) + + class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSerializer): """Establishment create serializer""" @@ -39,8 +49,6 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria queryset=models.Address.objects.all(), write_only=True ) - emails = model_serializers.ContactEmailsSerializer(read_only=True, - many=True, ) socials = model_serializers.SocialNetworkRelatedSerializers(read_only=True, many=True, ) type = model_serializers.EstablishmentTypeBaseSerializer(source='establishment_type', @@ -55,6 +63,13 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria child=serializers.CharField(max_length=128), required=False, ) + emails = serializers.ListField( + source='contact_emails', + allow_null=True, + allow_empty=True, + child=serializers.CharField(max_length=128), + required=False, + ) class Meta: model = models.Establishment @@ -87,8 +102,13 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria if 'contact_phones' in validated_data: phones_list = validated_data.pop('contact_phones') + emails_list = [] + if 'contact_emails' in validated_data: + emails_list = validated_data.pop('contact_emails') + instance = super().create(validated_data) phones_handler(phones_list, instance) + emails_handler(emails_list, instance) return instance @@ -113,8 +133,13 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): queryset=models.EstablishmentType.objects.all(), write_only=True ) address = AddressDetailSerializer() - emails = model_serializers.ContactEmailsSerializer(read_only=False, - many=True, ) + emails = serializers.ListField( + source='contact_emails', + allow_null=True, + allow_empty=True, + child=serializers.CharField(max_length=128), + required=False, + ) socials = model_serializers.SocialNetworkRelatedSerializers(read_only=False, many=True, ) type = model_serializers.EstablishmentTypeBaseSerializer(source='establishment_type') @@ -152,8 +177,13 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): if 'contact_phones' in validated_data: phones_list = validated_data.pop('contact_phones') + emails_list = [] + if 'contact_emails' in validated_data: + emails_list = validated_data.pop('contact_emails') + instance = super().update(instance, validated_data) phones_handler(phones_list, instance) + emails_handler(emails_list, instance) return instance diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index dfd5ded7..d745f5e9 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -19,7 +19,7 @@ class EstablishmentMixinViews: def get_queryset(self): """Overrided method 'get_queryset'.""" - return models.Establishment.objects.with_base_related() + return models.Establishment.objects.with_base_related().with_contacts() class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAPIView): From e89f04dee4158e2cf5fb8634b58a7f131e22d6a5 Mon Sep 17 00:00:00 2001 From: dormantman Date: Tue, 28 Jan 2020 14:44:46 +0300 Subject: [PATCH 054/101] Added serializer parent region --- apps/location/serializers/common.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/apps/location/serializers/common.py b/apps/location/serializers/common.py index 8b44f440..ff356be4 100644 --- a/apps/location/serializers/common.py +++ b/apps/location/serializers/common.py @@ -34,6 +34,27 @@ class CountrySimpleSerializer(serializers.ModelSerializer): fields = ('id', 'code', 'name_translated') +class ParentRegionSerializer(serializers.ModelSerializer): + """Region serializer""" + + country = CountrySerializer(read_only=True) + country_id = serializers.PrimaryKeyRelatedField( + source='country', + queryset=models.Country.objects.all(), + write_only=True + ) + + class Meta: + model = models.Region + fields = [ + 'id', + 'name', + 'code', + 'country', + 'country_id' + ] + + class RegionSerializer(serializers.ModelSerializer): """Region serializer""" @@ -43,6 +64,7 @@ class RegionSerializer(serializers.ModelSerializer): queryset=models.Country.objects.all(), write_only=True ) + parent_region = ParentRegionSerializer(read_only=True) class Meta: model = models.Region From 475de626cea95caab7187e2f4d663f7e8a306524 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 14:50:43 +0300 Subject: [PATCH 055/101] fix news update --- apps/news/serializers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 3103c4dd..35db45d1 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -362,8 +362,9 @@ class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer, template_display = serializers.CharField(source='get_template_display', read_only=True) duplicates = NewsBackOfficeDuplicationInfoSerializer(many=True, allow_null=True, read_only=True) + agenda = AgendaSerializer(required=False, allow_null=True, read_only=True) - class Meta(NewsBackOfficeBaseSerializer.Meta, NewsDetailSerializer.Meta): + class Meta(NewsDetailSerializer.Meta, NewsBackOfficeBaseSerializer.Meta): """Meta class.""" fields = NewsBackOfficeBaseSerializer.Meta.fields + \ From baeb7e5b930c807b6590fe2ecd604298b66039bf Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 14:55:13 +0300 Subject: [PATCH 056/101] fix news update --- apps/news/serializers.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 35db45d1..2ddae3c1 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -379,6 +379,30 @@ class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer, 'duplicates', ) + def validate(self, attrs): + """Overridden validate method.""" + if 'descriptions' in attrs: + descriptions = attrs.pop('descriptions') + locales = list(map(lambda x: x['locale'], descriptions)) + status_to_bool = { + 'active': True, + 'inactive': False, + } + attrs['slugs'] = {obj['locale']: obj['slug'] for obj in descriptions if 'slug' in obj} + attrs['title'] = {obj['locale']: obj['title'] for obj in descriptions if 'title' in obj} + attrs['locale_to_description_is_active'] = { + obj['locale']: status_to_bool[obj['status']] for obj in descriptions + } + attrs['description'] = {obj['locale']: obj['text'] for obj in descriptions if 'text' in obj} + if self.context['request'].method == 'PATCH': + instance = models.News.objects.get(pk=self.context['request'].data['id']) + for key in ['slugs', 'title', 'locale_to_description_is_active', 'description']: + for locale in locales: + if not attrs[key].get(locale): + attrs[key][locale] = getattr(instance, key).get(locale) + + return attrs + class NewsBackOfficeGallerySerializer(serializers.ModelSerializer): """Serializer class for model NewsGallery.""" From 4c7088abbcc237827eb3d061c66406dfbfdeaeab Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 14:58:41 +0300 Subject: [PATCH 057/101] fix news again... --- apps/news/serializers.py | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 2ddae3c1..a6b2d72d 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -379,29 +379,29 @@ class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer, 'duplicates', ) - def validate(self, attrs): - """Overridden validate method.""" - if 'descriptions' in attrs: - descriptions = attrs.pop('descriptions') - locales = list(map(lambda x: x['locale'], descriptions)) - status_to_bool = { - 'active': True, - 'inactive': False, - } - attrs['slugs'] = {obj['locale']: obj['slug'] for obj in descriptions if 'slug' in obj} - attrs['title'] = {obj['locale']: obj['title'] for obj in descriptions if 'title' in obj} - attrs['locale_to_description_is_active'] = { - obj['locale']: status_to_bool[obj['status']] for obj in descriptions - } - attrs['description'] = {obj['locale']: obj['text'] for obj in descriptions if 'text' in obj} - if self.context['request'].method == 'PATCH': - instance = models.News.objects.get(pk=self.context['request'].data['id']) - for key in ['slugs', 'title', 'locale_to_description_is_active', 'description']: - for locale in locales: - if not attrs[key].get(locale): - attrs[key][locale] = getattr(instance, key).get(locale) + def validate(self, attrs): + """Overridden validate method.""" + if 'descriptions' in attrs: + descriptions = attrs.pop('descriptions') + locales = list(map(lambda x: x['locale'], descriptions)) + status_to_bool = { + 'active': True, + 'inactive': False, + } + attrs['slugs'] = {obj['locale']: obj['slug'] for obj in descriptions if 'slug' in obj} + attrs['title'] = {obj['locale']: obj['title'] for obj in descriptions if 'title' in obj} + attrs['locale_to_description_is_active'] = { + obj['locale']: status_to_bool[obj['status']] for obj in descriptions + } + attrs['description'] = {obj['locale']: obj['text'] for obj in descriptions if 'text' in obj} + if self.context['request'].method == 'PATCH': + instance = models.News.objects.get(pk=self.context['request'].data['id']) + for key in ['slugs', 'title', 'locale_to_description_is_active', 'description']: + for locale in locales: + if not attrs[key].get(locale): + attrs[key][locale] = getattr(instance, key).get(locale) - return attrs + return attrs class NewsBackOfficeGallerySerializer(serializers.ModelSerializer): From 8f752ae6a097f19e5470f969bbb16d3802bd3c82 Mon Sep 17 00:00:00 2001 From: "a.gorbunov" Date: Tue, 28 Jan 2020 12:05:30 +0000 Subject: [PATCH 058/101] tune get comments method --- apps/comment/models.py | 3 +++ apps/comment/serializers/common.py | 37 +++++++++++++++++++++--------- apps/comment/urls/back.py | 2 ++ apps/comment/views/back.py | 22 ++++++++++++++++-- 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/apps/comment/models.py b/apps/comment/models.py index a7645ed0..3eac6480 100644 --- a/apps/comment/models.py +++ b/apps/comment/models.py @@ -48,6 +48,9 @@ class CommentQuerySet(ContentTypeQuerySetMixin): qs = self.filter(id__in=tuple(waiting_ids)) return qs + def with_base_related(self): + return self.prefetch_related("content_object").select_related("user", "content_type") + class Comment(ProjectBaseMixin): """Comment model.""" diff --git a/apps/comment/serializers/common.py b/apps/comment/serializers/common.py index c928aca4..2f1cdd5d 100644 --- a/apps/comment/serializers/common.py +++ b/apps/comment/serializers/common.py @@ -1,9 +1,8 @@ """Common serializers for app comment.""" +from django.utils.text import slugify from rest_framework import serializers -import establishment.serializers.common as establishment_serializers from comment.models import Comment -from establishment.models import EstablishmentType class CommentBaseSerializer(serializers.ModelSerializer): @@ -22,6 +21,8 @@ class CommentBaseSerializer(serializers.ModelSerializer): user_email = serializers.CharField(read_only=True, source='user.email') + slug = serializers.SerializerMethodField(read_only=True) + class Meta: """Serializer for model Comment""" model = Comment @@ -39,18 +40,32 @@ class CommentBaseSerializer(serializers.ModelSerializer): 'status_display', 'last_ip', 'content_type', - 'content_name' + 'content_name', + 'slug', ] extra_kwargs = { # 'status': {'read_only': True}, } - def get_content_type(self, instance: Comment): - if instance.content_object.establishment_type == EstablishmentType.PRODUCER: - return establishment_serializers.EstablishmentSubTypeBaseSerializer( - instance.content_object.establishment_subtypes, many=True - ).data + def get_slug(self, instance: Comment) -> str: + return slugify(f"comment_{instance.content_object.name}_{instance.id}") - return establishment_serializers.EstablishmentTypeBaseSerializer( - instance.content_object.establishment_type - ).data + def get_content_type(self, instance: Comment): + import establishment.serializers.common as establishment_serializers + from establishment.models import EstablishmentType, Establishment + from product.models import Product + from product.serializers import ProductTypeBaseSerializer + + if isinstance(instance.content_object, Establishment): + if instance.content_object.establishment_type == EstablishmentType.PRODUCER: + return establishment_serializers.EstablishmentSubTypeBaseSerializer( + instance.content_object.establishment_subtypes, many=True + ).data + + return establishment_serializers.EstablishmentTypeBaseSerializer( + instance.content_object.establishment_type + ).data + if isinstance(instance.content_object, Product): + return ProductTypeBaseSerializer( + instance.content_object.product_type + ).data diff --git a/apps/comment/urls/back.py b/apps/comment/urls/back.py index 214eab48..d2d693f9 100644 --- a/apps/comment/urls/back.py +++ b/apps/comment/urls/back.py @@ -7,5 +7,7 @@ app_name = 'comment' urlpatterns = [ path('', views.CommentLstView.as_view(), name='comment-list-create'), + path('/', views.CommentLstView.as_view(), name='comment-list-by-type-create'), + path('/', views.CommentLstView.as_view(), name='comment-list-by-type-object-create'), path('/', views.CommentRUDView.as_view(), name='comment-crud'), ] diff --git a/apps/comment/views/back.py b/apps/comment/views/back.py index a3c05543..04df4ad0 100644 --- a/apps/comment/views/back.py +++ b/apps/comment/views/back.py @@ -8,10 +8,28 @@ from utils.permissions import IsCommentModerator class CommentLstView(generics.ListCreateAPIView): """Comment list create view.""" serializer_class = CommentBaseSerializer - queryset = models.Comment.objects.all() - # permission_classes = [permissions.IsAuthenticatedOrReadOnly| IsCommentModerator|IsCountryAdmin] + def get_queryset(self): + from product.models import Product + from establishment.models import Establishment + + allowed = { + "product": Product.__name__.lower(), + "establishment": Establishment.__name__.lower() + } + + qs = models.Comment.objects.with_base_related() + + if "object" in self.kwargs: + qs = qs.by_object_id(self.kwargs["object"]) + + if "type" in self.kwargs and self.kwargs["type"] in allowed: + model = allowed[self.kwargs["type"]] + qs = qs.by_content_type(self.kwargs["type"], model) + + return qs.extra(order_by=['-created']) + class CommentRUDView(generics.RetrieveUpdateDestroyAPIView): """Comment RUD view.""" From 3b7b778a8ebe697281e47b7d85513d435fd04d20 Mon Sep 17 00:00:00 2001 From: dormantman Date: Tue, 28 Jan 2020 15:09:51 +0300 Subject: [PATCH 059/101] Change sending subscription searcher --- apps/notification/models.py | 6 +++--- apps/notification/serializers/common.py | 4 ++-- apps/notification/tasks.py | 8 ++++---- apps/notification/views/common.py | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/notification/models.py b/apps/notification/models.py index a176034e..4de7d94f 100644 --- a/apps/notification/models.py +++ b/apps/notification/models.py @@ -133,7 +133,7 @@ class Subscriber(ProjectBaseMixin): self.update_code = generate_string_code() return super(Subscriber, self).save(*args, **kwargs) - def unsubscribe(self, query: dict): + def unsubscribe(self): """Unsubscribe user.""" self.subscribe_set.update( @@ -147,9 +147,9 @@ class Subscriber(ProjectBaseMixin): ) if settings.USE_CELERY: - send_unsubscribe_email.delay(self.email) + send_unsubscribe_email.delay(self.pk) else: - send_unsubscribe_email(self.email) + send_unsubscribe_email(self.pk) @property def send_to(self): diff --git a/apps/notification/serializers/common.py b/apps/notification/serializers/common.py index 282a763c..3a061498 100644 --- a/apps/notification/serializers/common.py +++ b/apps/notification/serializers/common.py @@ -90,9 +90,9 @@ class CreateAndUpdateSubscribeSerializer(serializers.ModelSerializer): subscriber = models.Subscriber.objects.make_subscriber(**validated_data) if settings.USE_CELERY: - send_subscribes_update_email.delay(subscriber.email) + send_subscribes_update_email.delay(subscriber.pk) else: - send_subscribes_update_email(subscriber.email) + send_subscribes_update_email(subscriber.pk) return subscriber diff --git a/apps/notification/tasks.py b/apps/notification/tasks.py index cea15287..74f0e814 100644 --- a/apps/notification/tasks.py +++ b/apps/notification/tasks.py @@ -11,8 +11,8 @@ from django.utils.translation import gettext_lazy as _ @shared_task -def send_subscribes_update_email(email): - subscriber = models.Subscriber.objects.filter(email=email).first() +def send_subscribes_update_email(subscriber_id): + subscriber = models.Subscriber.objects.get(pk=subscriber_id) if subscriber is None: return @@ -53,8 +53,8 @@ def send_subscribes_update_email(email): @shared_task -def send_unsubscribe_email(email): - subscriber = models.Subscriber.objects.filter(email=email).first() +def send_unsubscribe_email(subscriber_id): + subscriber = models.Subscriber.objects.get(pk=subscriber_id) if subscriber is None: return diff --git a/apps/notification/views/common.py b/apps/notification/views/common.py index 39fa55f3..0c97930d 100644 --- a/apps/notification/views/common.py +++ b/apps/notification/views/common.py @@ -70,7 +70,7 @@ class UnsubscribeView(generics.UpdateAPIView): def put(self, request, *args, **kw): obj = self.get_object() - obj.unsubscribe(request.query_params) + obj.unsubscribe() serializer = self.get_serializer(instance=obj) return Response(data=serializer.data) @@ -85,7 +85,7 @@ class UnsubscribeAuthUserView(generics.GenericAPIView): def patch(self, request, *args, **kw): user = request.user obj = models.Subscriber.objects.filter(user=user).first() - obj.unsubscribe(request.query_params) + obj.unsubscribe() serializer = self.get_serializer(instance=obj) return Response(data=serializer.data) From 028b8475b780e65a804fabfa0eaa80c404b80ea2 Mon Sep 17 00:00:00 2001 From: "a.gorbunov" Date: Tue, 28 Jan 2020 12:16:18 +0000 Subject: [PATCH 060/101] slug from content object --- apps/comment/serializers/common.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/comment/serializers/common.py b/apps/comment/serializers/common.py index 2f1cdd5d..592534fd 100644 --- a/apps/comment/serializers/common.py +++ b/apps/comment/serializers/common.py @@ -1,5 +1,4 @@ """Common serializers for app comment.""" -from django.utils.text import slugify from rest_framework import serializers from comment.models import Comment @@ -21,7 +20,7 @@ class CommentBaseSerializer(serializers.ModelSerializer): user_email = serializers.CharField(read_only=True, source='user.email') - slug = serializers.SerializerMethodField(read_only=True) + slug = serializers.CharField(read_only=True, source='content_object.slug') class Meta: """Serializer for model Comment""" @@ -47,9 +46,6 @@ class CommentBaseSerializer(serializers.ModelSerializer): # 'status': {'read_only': True}, } - def get_slug(self, instance: Comment) -> str: - return slugify(f"comment_{instance.content_object.name}_{instance.id}") - def get_content_type(self, instance: Comment): import establishment.serializers.common as establishment_serializers from establishment.models import EstablishmentType, Establishment From a0a6e98fa6592b1fe3a3a198c10a107e98951f34 Mon Sep 17 00:00:00 2001 From: "a.gorbunov" Date: Tue, 28 Jan 2020 12:32:18 +0000 Subject: [PATCH 061/101] resolve comments --- apps/comment/views/back.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/comment/views/back.py b/apps/comment/views/back.py index 04df4ad0..68ae9a90 100644 --- a/apps/comment/views/back.py +++ b/apps/comment/views/back.py @@ -7,9 +7,6 @@ from utils.permissions import IsCommentModerator class CommentLstView(generics.ListCreateAPIView): """Comment list create view.""" - serializer_class = CommentBaseSerializer - # permission_classes = [permissions.IsAuthenticatedOrReadOnly| IsCommentModerator|IsCountryAdmin] - def get_queryset(self): from product.models import Product from establishment.models import Establishment @@ -28,7 +25,10 @@ class CommentLstView(generics.ListCreateAPIView): model = allowed[self.kwargs["type"]] qs = qs.by_content_type(self.kwargs["type"], model) - return qs.extra(order_by=['-created']) + return qs.order_by('-created') + + serializer_class = CommentBaseSerializer + # permission_classes = [permissions.IsAuthenticatedOrReadOnly| IsCommentModerator|IsCountryAdmin] class CommentRUDView(generics.RetrieveUpdateDestroyAPIView): From d0e75ca07cac5d183b063d54dfa410629f3c990a Mon Sep 17 00:00:00 2001 From: dormantman Date: Tue, 28 Jan 2020 15:46:23 +0300 Subject: [PATCH 062/101] Added instagram/western_name fields --- apps/establishment/models.py | 4 ++++ apps/establishment/serializers/back.py | 2 ++ apps/establishment/serializers/common.py | 1 + 3 files changed, 7 insertions(+) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index fbe333cf..b1adf435 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -528,6 +528,8 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, name = models.CharField(_('name'), max_length=255, default='') transliterated_name = models.CharField(default='', max_length=255, verbose_name=_('Transliterated name')) + western_name = models.CharField(default='', max_length=255, + verbose_name=_('Western name')) index_name = models.CharField(_('Index name'), max_length=255, default='') description = TJSONField(blank=True, null=True, default=None, verbose_name=_('description'), @@ -559,6 +561,8 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, verbose_name=_('Facebook URL')) twitter = models.URLField(blank=True, null=True, default=None, max_length=255, verbose_name=_('Twitter URL')) + instagram =models.URLField(blank=True, null=True, default=None, max_length=255, + verbose_name=_('Instagram URL')) lafourchette = models.URLField(blank=True, null=True, default=None, max_length=255, verbose_name=_('Lafourchette URL')) guestonline_id = models.PositiveIntegerField(blank=True, verbose_name=_('guestonline id'), diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index cf463454..8d02f252 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -156,6 +156,7 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): fields = [ 'id', 'slug', + 'western_name', 'name', 'website', 'phones', @@ -169,6 +170,7 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): # TODO: check in admin filters 'is_publish', 'address', + 'transportation', 'tags', ] diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index cd60e9f1..5d53eec8 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -464,6 +464,7 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer): 'website', 'facebook', 'twitter', + 'instagram', 'lafourchette', 'booking', 'phones', From 56b5af12915639ed54164a00d8837e96a143c090 Mon Sep 17 00:00:00 2001 From: dormantman Date: Tue, 28 Jan 2020 15:49:00 +0300 Subject: [PATCH 063/101] Added district_name field --- apps/location/models.py | 2 ++ apps/location/serializers/common.py | 1 + 2 files changed, 3 insertions(+) diff --git a/apps/location/models.py b/apps/location/models.py index 5b2fa721..a50b1f41 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -223,6 +223,8 @@ class Address(models.Model): default='', help_text=_('Ex.: 350018')) coordinates = models.PointField( _('Coordinates'), blank=True, null=True, default=None) + district_name = models.CharField( + _('District name'), max_length=500, blank=True, default='') old_id = models.IntegerField(null=True, blank=True, default=None) class Meta: diff --git a/apps/location/serializers/common.py b/apps/location/serializers/common.py index ff356be4..00fc893a 100644 --- a/apps/location/serializers/common.py +++ b/apps/location/serializers/common.py @@ -171,6 +171,7 @@ class AddressBaseSerializer(serializers.ModelSerializer): 'postal_code', 'latitude', 'longitude', + 'district_name', # todo: remove this fields (backward compatibility) 'geo_lon', From 191c168c991fa30da3f7041e5b558a24d40a9389 Mon Sep 17 00:00:00 2001 From: dormantman Date: Tue, 28 Jan 2020 15:49:50 +0300 Subject: [PATCH 064/101] Added migrations --- .../0082_establishment_western_name.py | 18 ++++++++++++++++++ .../migrations/0083_establishment_instagram.py | 18 ++++++++++++++++++ .../migrations/0037_address_district_name.py | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 apps/establishment/migrations/0082_establishment_western_name.py create mode 100644 apps/establishment/migrations/0083_establishment_instagram.py create mode 100644 apps/location/migrations/0037_address_district_name.py diff --git a/apps/establishment/migrations/0082_establishment_western_name.py b/apps/establishment/migrations/0082_establishment_western_name.py new file mode 100644 index 00000000..a5c5e942 --- /dev/null +++ b/apps/establishment/migrations/0082_establishment_western_name.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.7 on 2020-01-28 12:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0081_menuuploads_title'), + ] + + operations = [ + migrations.AddField( + model_name='establishment', + name='western_name', + field=models.CharField(default='', max_length=255, verbose_name='Western name'), + ), + ] diff --git a/apps/establishment/migrations/0083_establishment_instagram.py b/apps/establishment/migrations/0083_establishment_instagram.py new file mode 100644 index 00000000..e5733f6d --- /dev/null +++ b/apps/establishment/migrations/0083_establishment_instagram.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.7 on 2020-01-28 12:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0082_establishment_western_name'), + ] + + operations = [ + migrations.AddField( + model_name='establishment', + name='instagram', + field=models.URLField(blank=True, default=None, max_length=255, null=True, verbose_name='Instagram URL'), + ), + ] diff --git a/apps/location/migrations/0037_address_district_name.py b/apps/location/migrations/0037_address_district_name.py new file mode 100644 index 00000000..294989e6 --- /dev/null +++ b/apps/location/migrations/0037_address_district_name.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.7 on 2020-01-28 12:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('location', '0036_auto_20200127_2004'), + ] + + operations = [ + migrations.AddField( + model_name='address', + name='district_name', + field=models.CharField(blank=True, default='', max_length=500, verbose_name='District name'), + ), + ] From 121b91709676956429423c5018c708aa9282699d Mon Sep 17 00:00:00 2001 From: "a.gorbunov" Date: Tue, 28 Jan 2020 13:56:32 +0000 Subject: [PATCH 065/101] fix route --- apps/comment/urls/back.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/comment/urls/back.py b/apps/comment/urls/back.py index d2d693f9..79b5429e 100644 --- a/apps/comment/urls/back.py +++ b/apps/comment/urls/back.py @@ -7,7 +7,7 @@ app_name = 'comment' urlpatterns = [ path('', views.CommentLstView.as_view(), name='comment-list-create'), + path('/', views.CommentRUDView.as_view(), name='comment-crud'), path('/', views.CommentLstView.as_view(), name='comment-list-by-type-create'), path('/', views.CommentLstView.as_view(), name='comment-list-by-type-object-create'), - path('/', views.CommentRUDView.as_view(), name='comment-crud'), ] From 4604c81ede5dad58364560604af445e3be5202d4 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 17:50:38 +0300 Subject: [PATCH 066/101] change news states --- .../migrations/0053_auto_20200128_1431.py | 18 +++++++++++++++ apps/news/models.py | 22 +++++++++++-------- apps/news/views.py | 5 +++-- 3 files changed, 34 insertions(+), 11 deletions(-) create mode 100644 apps/news/migrations/0053_auto_20200128_1431.py diff --git a/apps/news/migrations/0053_auto_20200128_1431.py b/apps/news/migrations/0053_auto_20200128_1431.py new file mode 100644 index 00000000..b759a1a7 --- /dev/null +++ b/apps/news/migrations/0053_auto_20200128_1431.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.7 on 2020-01-28 14:31 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0052_auto_20200121_0940'), + ] + + operations = [ + migrations.AlterField( + model_name='news', + name='state', + field=models.PositiveSmallIntegerField(choices=[(0, 'remove'), (1, 'hidden'), (2, 'published'), (3, 'not published')], default=3, verbose_name='State'), + ), + ] diff --git a/apps/news/models.py b/apps/news/models.py index 3a529cc4..758269b8 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -101,6 +101,10 @@ class NewsQuerySet(TranslationQuerysetMixin): """Return qs with related objects.""" return self.select_related('created_by', 'agenda', 'banner') + def visible(self): + """Narrows qs by excluding invisible for API (at all) news""" + return self.exclude(state=self.model.REMOVE) + def by_type(self, news_type): """Filter News by type""" return self.filter(news_type__name=news_type) @@ -259,18 +263,18 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin, ) # STATE CHOICES - WAITING = 0 + REMOVE = 0 HIDDEN = 1 PUBLISHED = 2 - PUBLISHED_EXCLUSIVE = 3 + UNPUBLISHED = 3 - PUBLISHED_STATES = [PUBLISHED, PUBLISHED_EXCLUSIVE] + PUBLISHED_STATES = [PUBLISHED] STATE_CHOICES = ( - (WAITING, _('Waiting')), - (HIDDEN, _('Hidden')), - (PUBLISHED, _('Published')), - (PUBLISHED_EXCLUSIVE, _('Published exclusive')), + (REMOVE, _('remove')), # simply stored in DB news. not shown anywhere + (HIDDEN, _('hidden')), # not shown in api/web or api/mobile + (PUBLISHED, _('published')), # shown everywhere + (UNPUBLISHED, _('not published')), # newly created news ) INTERNATIONAL_TAG_VALUE = 'international' @@ -302,7 +306,7 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin, slugs = HStoreField(null=True, blank=True, default=dict, verbose_name=_('Slugs for current news obj'), help_text='{"en-GB":"some slug"}') - state = models.PositiveSmallIntegerField(default=WAITING, choices=STATE_CHOICES, + state = models.PositiveSmallIntegerField(default=UNPUBLISHED, choices=STATE_CHOICES, verbose_name=_('State')) is_highlighted = models.BooleanField(default=False, verbose_name=_('Is highlighted')) @@ -347,7 +351,7 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin, def create_duplicate(self, new_country, view_count_model): self.pk = None - self.state = self.WAITING + self.state = self.UNPUBLISHED self.slugs = {locale: f'{slug}-{new_country.code}' for locale, slug in self.slugs.items()} self.country = new_country self.views_count = view_count_model diff --git a/apps/news/views.py b/apps/news/views.py index c98a3c18..d4479b3c 100644 --- a/apps/news/views.py +++ b/apps/news/views.py @@ -11,7 +11,7 @@ from news import filters, models, serializers from rating.tasks import add_rating from utils.permissions import IsCountryAdmin, IsContentPageManager from utils.views import CreateDestroyGalleryViewMixin, FavoritesCreateDestroyMixinView, CarouselCreateDestroyMixinView -from utils.serializers import ImageBaseSerializer, EmptySerializer +from utils.serializers import ImageBaseSerializer class NewsMixinView: @@ -24,6 +24,7 @@ class NewsMixinView: """Override get_queryset method.""" qs = models.News.objects.published() \ .with_base_related() \ + .visible() \ .annotate_in_favorites(self.request.user) \ .order_by('-is_highlighted', '-publication_date', '-publication_time') @@ -41,7 +42,7 @@ class NewsMixinView: return qs def get_object(self): - instance = self.get_queryset().filter( + instance = self.get_queryset().visible().with_base_related().filter( slugs__values__contains=[self.kwargs['slug']] ).first() From 61d2f6ec46a6cb9371aa6e5dbb530709526165ce Mon Sep 17 00:00:00 2001 From: Anatoly Date: Tue, 28 Jan 2020 17:52:38 +0300 Subject: [PATCH 067/101] added filter - establishment_id, refactored guide counters --- apps/collection/filters.py | 56 ++++++++++++++++++++ apps/collection/models.py | 73 ++++++++++++++++++++------- apps/collection/serializers/common.py | 2 + apps/collection/views/back.py | 23 +++------ apps/establishment/filters.py | 3 +- apps/establishment/urls/common.py | 2 +- 6 files changed, 122 insertions(+), 37 deletions(-) create mode 100644 apps/collection/filters.py diff --git a/apps/collection/filters.py b/apps/collection/filters.py new file mode 100644 index 00000000..66b5e454 --- /dev/null +++ b/apps/collection/filters.py @@ -0,0 +1,56 @@ +"""Collection app filters.""" +from django_filters import rest_framework as filters +from django.core.validators import EMPTY_VALUES + +from collection import models + + +class CollectionFilterSet(filters.FilterSet): + """Collection filter set.""" + establishment_id = filters.NumberFilter( + field_name='establishments__id', + help_text='Establishment id. Allows to filter list of collections by choosen estblishment. ' + 'Use for Establishment detail\'s sheet to content display within ' + '"Collections & Guides" tab.' + ) + + # "ordering" instead of "o" is for backward compatibility + ordering = filters.OrderingFilter( + # tuple-mapping retains order + fields=( + ('rank', 'rank'), + ('start', 'start'), + ), + help_text='Ordering by fields - rank, start', + ) + + class Meta: + """Meta class.""" + model = models.Collection + fields = ( + 'ordering', + 'establishment_id', + ) + + +class GuideFilterSet(filters.FilterSet): + """Guide filter set.""" + establishment_id = filters.NumberFilter( + method='by_establishment_id', + help_text='Establishment id. Allows to filter list of guides by choosen establishment. ' + 'Use for Establishment detail\'s sheet to content display within ' + '"Collections & Guides" tab.' + ) + + class Meta: + """Meta class.""" + model = models.Guide + fields = ( + 'establishment_id', + ) + + def by_establishment_id(self, queryset, name, value): + """Filter by establishment id.""" + if value not in EMPTY_VALUES: + return queryset.by_establishment_id(value) + return queryset diff --git a/apps/collection/models.py b/apps/collection/models.py index 91173ed0..2fe28e4f 100644 --- a/apps/collection/models.py +++ b/apps/collection/models.py @@ -171,17 +171,26 @@ class GuideQuerySet(models.QuerySet): """Return QuerySet with related.""" return self.select_related('site', ) + def with_extended_related(self): + """Return QuerySet with extended related.""" + return self.with_base_related().prefetch_related('guideelement_set') + def by_country_id(self, country_id): """Return QuerySet filtered by country code.""" return self.filter(country_json__id__contains=country_id) def annotate_in_restaurant_section(self): """Annotate flag if GuideElement in RestaurantSectionNode.""" + restaurant_guides = models.Subquery( + self.filter( + guideelement__guide_element_type__name='EstablishmentNode', + guideelement__parent__guide_element_type__name='RestaurantSectionNode', + ).values_list('id', flat=True).distinct() + ) return self.annotate( in_restaurant_section=models.Case( models.When( - guideelement__guide_element_type__name='EstablishmentNode', - guideelement__parent__guide_element_type__name='RestaurantSectionNode', + id__in=restaurant_guides, then=True), default=False, output_field=models.BooleanField(default=False) @@ -190,11 +199,16 @@ class GuideQuerySet(models.QuerySet): def annotate_in_shop_section(self): """Annotate flag if GuideElement in ShopSectionNode.""" + shop_guides = models.Subquery( + self.filter( + guideelement__guide_element_type__name='EstablishmentNode', + guideelement__parent__guide_element_type__name='ShopSectionNode', + ).values_list('guideelement__id', flat=True).distinct() + ) return self.annotate( in_shop_section=models.Case( models.When( - guideelement__guide_element_type__name='EstablishmentNode', - guideelement__parent__guide_element_type__name='ShopSectionNode', + id__in=shop_guides, then=True), default=False, output_field=models.BooleanField(default=False) @@ -205,37 +219,60 @@ class GuideQuerySet(models.QuerySet): """Return QuerySet with annotated field - restaurant_counter.""" return self.annotate_in_restaurant_section().annotate( restaurant_counter=models.Count( - 'guideelement', + 'guideelement__establishment', filter=models.Q(in_restaurant_section=True) & - models.Q(guideelement__parent_id__isnull=False), - distinct=True)) + models.Q(guideelement__parent_id__isnull=True), + distinct=True + ) + ) def annotate_shop_counter(self): """Return QuerySet with annotated field - shop_counter.""" return self.annotate_in_shop_section().annotate( shop_counter=models.Count( - 'guideelement', + 'guideelement__establishment', filter=models.Q(in_shop_section=True) & - models.Q(guideelement__parent_id__isnull=False), - distinct=True)) + models.Q(guideelement__parent_id__isnull=True), + distinct=True + ) + ) def annotate_wine_counter(self): """Return QuerySet with annotated field - shop_counter.""" return self.annotate_in_restaurant_section().annotate( wine_counter=models.Count( - 'guideelement', + 'guideelement__product', filter=models.Q(guideelement__guide_element_type__name='WineNode') & models.Q(guideelement__parent_id__isnull=False), - distinct=True)) + distinct=True + ) + ) def annotate_present_objects_counter(self): """Return QuerySet with annotated field - present_objects_counter.""" - return self.annotate_in_restaurant_section().annotate( - present_objects_counter=models.Count( - 'guideelement', - filter=models.Q(guideelement__guide_element_type__name__in=['EstablishmentNode', 'WineNode']) & - models.Q(guideelement__parent_id__isnull=False), - distinct=True)) + return ( + self.annotate_restaurant_counter() + .annotate_shop_counter() + .annotate_wine_counter() + .annotate( + present_objects_counter=( + models.F('restaurant_counter') + + models.F('shop_counter') + + models.F('wine_counter') + ) + ) + ) + + def annotate_counters(self): + return ( + self.annotate_restaurant_counter() + .annotate_shop_counter() + .annotate_wine_counter() + .annotate_present_objects_counter() + ) + + def by_establishment_id(self, establishment_id: int): + return self.filter(guideelement__establishment=establishment_id).distinct() class Guide(ProjectBaseMixin, CollectionNameMixin, CollectionDateMixin): diff --git a/apps/collection/serializers/common.py b/apps/collection/serializers/common.py index da33d271..8943c7a2 100644 --- a/apps/collection/serializers/common.py +++ b/apps/collection/serializers/common.py @@ -109,6 +109,7 @@ class GuideBaseSerializer(serializers.ModelSerializer): restaurant_counter = serializers.IntegerField(read_only=True) shop_counter = serializers.IntegerField(read_only=True) wine_counter = serializers.IntegerField(read_only=True) + present_objects_counter = serializers.IntegerField(read_only=True) count_objects_during_init = serializers.IntegerField(read_only=True, source='count_related_objects') @@ -131,6 +132,7 @@ class GuideBaseSerializer(serializers.ModelSerializer): 'restaurant_counter', 'shop_counter', 'wine_counter', + 'present_objects_counter', 'count_objects_during_init', ] extra_kwargs = { diff --git a/apps/collection/views/back.py b/apps/collection/views/back.py index 73fb7b18..8b9d0d8e 100644 --- a/apps/collection/views/back.py +++ b/apps/collection/views/back.py @@ -1,13 +1,11 @@ from django.shortcuts import get_object_or_404 from django.utils.translation import gettext_lazy as _ -from django_filters.rest_framework import DjangoFilterBackend from rest_framework import generics from rest_framework import mixins, permissions, viewsets from rest_framework import status -from rest_framework.filters import OrderingFilter from rest_framework.response import Response -from collection import models, serializers +from collection import models, serializers, filters from collection import tasks from utils.views import BindObjectMixin @@ -34,12 +32,7 @@ class GuideBaseView(generics.GenericAPIView): def get_queryset(self): """Overridden get_queryset method.""" - return models.Guide.objects.with_base_related() \ - .annotate_restaurant_counter() \ - .annotate_shop_counter() \ - .annotate_wine_counter() \ - .annotate_present_objects_counter() \ - .distinct() + return models.Guide.objects.with_extended_related().annotate_counters() class GuideFilterBaseView(generics.GenericAPIView): @@ -72,17 +65,14 @@ class CollectionBackOfficeViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, BindObjectMixin, CollectionViewSet): - """ViewSet for Collection model for BackOffice users.""" + """ViewSet for Collections list for BackOffice users and Collection create.""" permission_classes = (permissions.IsAuthenticated,) - queryset = models.Collection.objects.with_base_related() - filter_backends = [DjangoFilterBackend, OrderingFilter] + queryset = models.Collection.objects.with_base_related().order_by('-start') + filter_class = filters.CollectionFilterSet serializer_class = serializers.CollectionBackOfficeSerializer bind_object_serializer_class = serializers.CollectionBindObjectSerializer - ordering_fields = ('rank', 'start') - ordering = ('-start', ) - def perform_binding(self, serializer): data = serializer.validated_data collection = data.pop('collection') @@ -106,7 +96,8 @@ class CollectionBackOfficeViewSet(mixins.CreateModelMixin, class GuideListCreateView(GuideBaseView, generics.ListCreateAPIView): - """View for Guide model for BackOffice users.""" + """View for Guides list for BackOffice users and Guide create.""" + filter_class = filters.GuideFilterSet class GuideFilterCreateView(GuideFilterBaseView, diff --git a/apps/establishment/filters.py b/apps/establishment/filters.py index b52c909f..86d5b787 100644 --- a/apps/establishment/filters.py +++ b/apps/establishment/filters.py @@ -1,8 +1,7 @@ """Establishment app filters.""" from django.core.validators import EMPTY_VALUES from django.utils.translation import ugettext_lazy as _ -from django_filters import rest_framework as filters, Filter -from django_filters.fields import Lookup +from django_filters import rest_framework as filters from rest_framework.serializers import ValidationError from establishment import models diff --git a/apps/establishment/urls/common.py b/apps/establishment/urls/common.py index 0bb13cf6..25f2b14f 100644 --- a/apps/establishment/urls/common.py +++ b/apps/establishment/urls/common.py @@ -15,7 +15,7 @@ urlpatterns = [ name='create-comment'), path('slug//comments//', views.EstablishmentCommentRUDView.as_view(), name='rud-comment'), - path('slug//favorites/', views.EstablishmentFavoritesCreateDestroyView.as_view(), + path('slug//collections/', views.EstablishmentFavoritesCreateDestroyView.as_view(), name='create-destroy-favorites'), # similar establishments by type/subtype From 9af6458dffd5f61715ab6b82d83d4460712853ce Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 18:20:55 +0300 Subject: [PATCH 068/101] translations for news types --- project/locale/de/LC_MESSAGES/django.mo | Bin 0 -> 380 bytes project/locale/fr/LC_MESSAGES/django.mo | Bin 0 -> 534 bytes project/locale/fr/LC_MESSAGES/django.po | 2399 +++++++++++++- project/locale/ru/LC_MESSAGES/django.mo | Bin 0 -> 888 bytes project/locale/ru/LC_MESSAGES/django.po | 4045 ++++++++++------------- 5 files changed, 4121 insertions(+), 2323 deletions(-) create mode 100644 project/locale/de/LC_MESSAGES/django.mo create mode 100644 project/locale/fr/LC_MESSAGES/django.mo create mode 100644 project/locale/ru/LC_MESSAGES/django.mo diff --git a/project/locale/de/LC_MESSAGES/django.mo b/project/locale/de/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..71cbdf3e9d8d54be31066ec4ad8628bc2c1f2845 GIT binary patch literal 380 zcmYL@K~KUk7=|%=+R?Lz&%}d9i{c3jGZa>EvE7z2Nc2{r&Y96JZ6W$Y{CoZuJ5A(G zp7i_Dx9RhJeDu}vIq;l#&OC>nD^HugXY4QU{MmN?lNtRkR}RH%w3NnHT4Bh@vF%H^(V-=Ii1iQ$Qo9Pt!I1Rhe%oml#`f^NEGFCKEL->Rc=KoQ6a?!10%_7(V7ey8`V`;n{war z20Z3;uifk31QV^CRQ|iq#``$=;jWunRB8aLH({)F;i8zL{=V00y-I_qTIqGAN(}v% i$^}`yHKImSZ8jEzYJOK6-VWez49^vuhS0kh1f3tbb!oc* literal 0 HcmV?d00001 diff --git a/project/locale/fr/LC_MESSAGES/django.mo b/project/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..70828c7eaaa31f603456a522442c99aa86afd8c1 GIT binary patch literal 534 zcmYL_y-ve06oms65CIlu29F?Q{w9=Cgdr|OBu$mJNU)j2q(-S7*$#p?fQ^Nf873Zr z_uw7a7`bVYdZkb2TyZQl=M)SoL-PKiY{r=3*wHO@KR}uBa@2^pH#WQedQsy8{>rEi~0`sndKh3 zq9nmljD3R6V=oG}uHz1MLuM@QYbH&>tkNE855f?2NJP;gjYtq46W>p0uXhBaGOt+9 zai6o1heFah8`Mb-!|=Ee+e+ut8AuQX5uL`~+un6gm9$*KcaJ6HvHZdAlm!#AiP9m{ zhTGPl-^K^ixjNP@*OjZ^>t literal 0 HcmV?d00001 diff --git a/project/locale/fr/LC_MESSAGES/django.po b/project/locale/fr/LC_MESSAGES/django.po index 7951deec..6fcf4319 100644 --- a/project/locale/fr/LC_MESSAGES/django.po +++ b/project/locale/fr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-01-21 11:48+0000\n" +"POT-Creation-Date: 2020-01-28 15:17+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,6 +17,2403 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: apps/account/admin.py:32 +msgid "Personal info" +msgstr "" + +#: apps/account/admin.py:36 +msgid "Subscription" +msgstr "" + +#: apps/account/admin.py:41 +msgid "Important dates" +msgstr "" + +#: apps/account/admin.py:42 +msgid "Permissions" +msgstr "" + +#: apps/account/admin.py:61 apps/establishment/models.py:1101 +#: apps/location/models.py:41 apps/product/models.py:49 +#: apps/product/models.py:87 +msgid "Name" +msgstr "" + +#: apps/account/apps.py:7 +msgid "Account" +msgstr "" + +#: apps/account/forms.py:15 +msgid "The two password fields didn't match." +msgstr "" + +#: apps/account/forms.py:16 +msgid "Password already in use." +msgstr "" + +#: apps/account/forms.py:19 +msgid "New password" +msgstr "" + +#: apps/account/forms.py:25 +msgid "New password confirmation" +msgstr "" + +#: apps/account/models.py:56 +msgid "Standard user" +msgstr "" + +#: apps/account/models.py:57 +msgid "Comments moderator" +msgstr "" + +#: apps/account/models.py:58 +msgid "Country admin" +msgstr "" + +#: apps/account/models.py:59 +msgid "Content page manager" +msgstr "" + +#: apps/account/models.py:60 +msgid "Establishment manager" +msgstr "" + +#: apps/account/models.py:61 +msgid "Reviewer manager" +msgstr "" + +#: apps/account/models.py:62 +msgid "Restaurant reviewer" +msgstr "" + +#: apps/account/models.py:63 +msgid "Sales man" +msgstr "" + +#: apps/account/models.py:64 +msgid "Winery reviewer" +msgstr "" + +#: apps/account/models.py:65 +msgid "Seller" +msgstr "" + +#: apps/account/models.py:66 +msgid "Liquor reviewer" +msgstr "" + +#: apps/account/models.py:67 +msgid "Product reviewer" +msgstr "" + +#: apps/account/models.py:70 apps/account/models.py:501 +msgid "Role" +msgstr "" + +#: apps/account/models.py:72 apps/establishment/models.py:1420 +#: apps/location/models.py:57 apps/main/models.py:61 apps/review/models.py:57 +msgid "Country" +msgstr "" + +#: apps/account/models.py:74 apps/main/models.py:88 +msgid "Site settings" +msgstr "" + +#: apps/account/models.py:77 apps/establishment/models.py:112 +msgid "Establishment subtype" +msgstr "" + +#: apps/account/models.py:83 +msgid "navigation bar permission" +msgstr "" + +#: apps/account/models.py:207 +msgid "username" +msgstr "" + +#: apps/account/models.py:210 +msgid "Required. 150 characters or fewer. Letters, digits and ./+/-/_ only." +msgstr "" + +#: apps/account/models.py:212 +msgid "A user with that username already exists." +msgstr "" + +#: apps/account/models.py:215 apps/news/models.py:49 apps/utils/models.py:270 +msgid "Image URL path" +msgstr "" + +#: apps/account/models.py:218 +msgid "Cropped image URL path" +msgstr "" + +#: apps/account/models.py:220 +msgid "email address" +msgstr "" + +#: apps/account/models.py:222 +msgid "unconfirmed email" +msgstr "" + +#: apps/account/models.py:223 +msgid "email status" +msgstr "" + +#: apps/account/models.py:227 +msgid "User last used locale" +msgstr "" + +#: apps/account/models.py:229 +msgid "User last visited from city" +msgstr "" + +#: apps/account/models.py:230 +msgid "last IP address" +msgstr "" + +#: apps/account/models.py:233 +msgid "last site settings" +msgstr "" + +#: apps/account/models.py:240 +msgid "Phone" +msgstr "" + +#: apps/account/models.py:247 +msgid "Roles" +msgstr "" + +#: apps/account/models.py:253 apps/account/models.py:499 +#: apps/comment/models.py:74 apps/establishment/models.py:1100 +#: apps/favorites/models.py:23 apps/notification/models.py:104 +msgid "User" +msgstr "" + +#: apps/account/models.py:254 +msgid "Users" +msgstr "" + +#: apps/account/models.py:492 +msgid "validated" +msgstr "" + +#: apps/account/models.py:493 +msgid "pending" +msgstr "" + +#: apps/account/models.py:494 +msgid "cancelled" +msgstr "" + +#: apps/account/models.py:495 +msgid "rejected" +msgstr "" + +#: apps/account/models.py:503 apps/establishment/apps.py:8 +#: apps/establishment/models.py:614 apps/establishment/models.py:975 +#: apps/partner/models.py:24 +msgid "Establishment" +msgstr "" + +#: apps/account/models.py:507 apps/collection/models.py:280 +#: apps/product/models.py:293 +msgid "state" +msgstr "" + +#: apps/account/models.py:521 +msgid "New role" +msgstr "" + +#: apps/account/models.py:522 +msgid "Old role" +msgstr "" + +#: apps/account/serializers/common.py:226 +msgid "Old password mismatch." +msgstr "" + +#: apps/account/serializers/common.py:229 apps/utils/exceptions.py:103 +msgid "Password is already in use" +msgstr "" + +#: apps/advertisement/apps.py:7 apps/main/models.py:359 +msgid "advertisement" +msgstr "" + +#: apps/advertisement/models.py:43 apps/collection/models.py:748 +#: apps/collection/models.py:968 apps/establishment/models.py:527 +#: apps/establishment/models.py:1288 apps/establishment/models.py:1353 +#: apps/location/models.py:286 apps/location/models.py:317 +#: apps/location/models.py:344 apps/main/models.py:258 apps/main/models.py:443 +#: apps/news/models.py:283 apps/notification/models.py:118 +#: apps/partner/models.py:18 apps/product/models.py:289 +#: apps/product/models.py:526 apps/product/models.py:592 +#: apps/recipe/models.py:61 apps/review/models.py:90 apps/review/models.py:130 +#: apps/review/models.py:158 apps/review/models.py:175 apps/tag/models.py:45 +msgid "old id" +msgstr "" + +#: apps/advertisement/models.py:45 +msgid "Ad URL" +msgstr "" + +#: apps/advertisement/models.py:46 +msgid "Block level" +msgstr "" + +#: apps/advertisement/models.py:48 apps/collection/models.py:39 +#: apps/collection/models.py:269 +msgid "start" +msgstr "" + +#: apps/advertisement/models.py:49 apps/collection/models.py:41 +msgid "end" +msgstr "" + +#: apps/advertisement/models.py:52 apps/comment/models.py:81 +#: apps/main/models.py:440 apps/tag/models.py:188 +msgid "site" +msgstr "" + +#: apps/advertisement/models.py:56 apps/main/models.py:392 +msgid "page type" +msgstr "" + +#: apps/advertisement/models.py:57 +msgid "display duration in seconds" +msgstr "" + +#: apps/advertisement/models.py:60 +msgid "Probability to show" +msgstr "" + +#: apps/advertisement/models.py:61 +msgid "How many times shown" +msgstr "" + +#: apps/advertisement/models.py:65 +msgid "Advertisement" +msgstr "" + +#: apps/advertisement/models.py:66 +msgid "Advertisements" +msgstr "" + +#: apps/authorization/apps.py:8 +msgid "Authorization" +msgstr "" + +#: apps/authorization/models.py:86 +msgid "Expiration datetime" +msgstr "" + +#: apps/authorization/models.py:94 +msgid "Access token" +msgstr "" + +#: apps/authorization/models.py:95 +msgid "Access tokens" +msgstr "" + +#: apps/authorization/models.py:154 +msgid "Refresh token" +msgstr "" + +#: apps/authorization/models.py:155 +msgid "Refresh tokens" +msgstr "" + +#: apps/authorization/tasks.py:18 apps/authorization/tasks.py:19 +msgid "Email confirmation" +msgstr "" + +#: apps/authorization/views/common.py:69 +msgid "Validation OAuth2 request data error" +msgstr "" + +#: apps/booking/apps.py:7 apps/booking/models/models.py:69 +#: apps/booking/models/models.py:70 +msgid "Booking" +msgstr "" + +#: apps/booking/models/models.py:21 +msgid "Guestonline or Lastable" +msgstr "" + +#: apps/booking/models/models.py:22 +msgid "booking service establishment id" +msgstr "" + +#: apps/booking/models/models.py:23 +msgid "booking locale" +msgstr "" + +#: apps/booking/models/models.py:24 +msgid "external service pending booking" +msgstr "" + +#: apps/booking/models/models.py:25 +msgid "external service booking id" +msgstr "" + +#: apps/booking/models/models.py:27 +msgid "stripe service payment key" +msgstr "" + +#: apps/booking/models/models.py:28 +msgid "stripe service pre-payed booking token" +msgstr "" + +#: apps/booking/models/models.py:29 +msgid "prepayment price" +msgstr "" + +#: apps/booking/models/models.py:31 +msgid "booking owner" +msgstr "" + +#: apps/booking/models/services.py:37 +msgid "This field is required" +msgstr "" + +#: apps/collection/apps.py:7 apps/collection/models.py:105 +msgid "collection" +msgstr "" + +#: apps/collection/models.py:29 apps/collection/models.py:78 +#: apps/collection/models.py:690 apps/establishment/models.py:528 +#: apps/establishment/models.py:1214 apps/establishment/models.py:1450 +#: apps/location/models.py:101 apps/location/models.py:280 +#: apps/location/models.py:313 apps/location/models.py:341 +#: apps/main/models.py:32 apps/main/models.py:223 apps/main/models.py:386 +#: apps/main/models.py:428 apps/news/models.py:64 +#: apps/notification/models.py:20 apps/partner/models.py:19 +#: apps/product/models.py:260 apps/product/models.py:490 +#: apps/product/models.py:521 apps/review/models.py:161 +msgid "name" +msgstr "" + +#: apps/collection/models.py:74 +msgid "Ordinary" +msgstr "" + +#: apps/collection/models.py:75 +msgid "Pop" +msgstr "" + +#: apps/collection/models.py:82 +msgid "Collection type" +msgstr "" + +#: apps/collection/models.py:84 apps/comment/models.py:76 +#: apps/establishment/models.py:574 +msgid "Publish status" +msgstr "" + +#: apps/collection/models.py:86 +msgid "Position on top" +msgstr "" + +#: apps/collection/models.py:88 apps/location/models.py:107 +#: apps/location/models.py:155 apps/location/models.py:283 +#: apps/main/models.py:222 apps/main/models.py:269 apps/news/models.py:319 +#: apps/notification/models.py:24 +msgid "country" +msgstr "" + +#: apps/collection/models.py:90 +msgid "collection block properties" +msgstr "" + +#: apps/collection/models.py:93 apps/establishment/models.py:535 +#: apps/establishment/models.py:1217 apps/location/models.py:289 +#: apps/main/models.py:434 apps/news/models.py:295 apps/product/models.py:261 +#: apps/review/models.py:163 +msgid "description" +msgstr "" + +#: apps/collection/models.py:96 +msgid "Collection slug" +msgstr "" + +#: apps/collection/models.py:106 +msgid "collections" +msgstr "" + +#: apps/collection/models.py:260 +msgid "Restaurant" +msgstr "" + +#: apps/collection/models.py:261 +msgid "Artisan" +msgstr "" + +#: apps/collection/models.py:262 +msgid "Wine" +msgstr "" + +#: apps/collection/models.py:267 +msgid "guide type" +msgstr "" + +#: apps/collection/models.py:273 +msgid "guide vintage year" +msgstr "" + +#: apps/collection/models.py:275 +msgid "slug" +msgstr "" + +#: apps/collection/models.py:278 apps/news/models.py:336 +msgid "site settings" +msgstr "" + +#: apps/collection/models.py:283 +msgid "* after rebuild guide, refresh count of related guide elements" +msgstr "" + +#: apps/collection/models.py:284 +msgid "count of related guide elements during initialization" +msgstr "" + +#: apps/collection/models.py:291 apps/collection/models.py:463 +msgid "guide" +msgstr "" + +#: apps/collection/models.py:292 +msgid "guides" +msgstr "" + +#: apps/collection/models.py:413 +msgid "number of pages" +msgstr "" + +#: apps/collection/models.py:414 +msgid "the total number of reserved pages" +msgstr "" + +#: apps/collection/models.py:416 +msgid "number of right pages" +msgstr "" + +#: apps/collection/models.py:417 +msgid "the number of right pages (which are part of total number)." +msgstr "" + +#: apps/collection/models.py:420 apps/collection/models.py:974 +msgid "guide element" +msgstr "" + +#: apps/collection/models.py:427 +msgid "advertorial" +msgstr "" + +#: apps/collection/models.py:428 +msgid "advertorials" +msgstr "" + +#: apps/collection/models.py:449 +msgid "with mark" +msgstr "" + +#: apps/collection/models.py:450 +msgid "exclude empty marks?" +msgstr "" + +#: apps/collection/models.py:453 +msgid "max mark" +msgstr "" + +#: apps/collection/models.py:455 +msgid "mark under" +msgstr "" + +#: apps/collection/models.py:456 +msgid "min mark" +msgstr "" + +#: apps/collection/models.py:458 +msgid "mark over" +msgstr "" + +#: apps/collection/models.py:470 +msgid "guide filter" +msgstr "" + +#: apps/collection/models.py:471 +msgid "guide filters" +msgstr "" + +#: apps/collection/models.py:694 apps/collection/models.py:943 +msgid "guide element type" +msgstr "" + +#: apps/collection/models.py:695 +msgid "guide element types" +msgstr "" + +#: apps/collection/models.py:709 apps/collection/models.py:744 +msgid "section name" +msgstr "" + +#: apps/collection/models.py:715 +msgid "guide wine color section" +msgstr "" + +#: apps/collection/models.py:716 +msgid "guide wine color sections" +msgstr "" + +#: apps/collection/models.py:727 +msgid "category name" +msgstr "" + +#: apps/collection/models.py:733 +msgid "guide element section category" +msgstr "" + +#: apps/collection/models.py:734 +msgid "guide element section categories" +msgstr "" + +#: apps/collection/models.py:746 apps/establishment/admin.py:121 +#: apps/establishment/models.py:1276 +msgid "category" +msgstr "" + +#: apps/collection/models.py:754 +msgid "guide element section" +msgstr "" + +#: apps/collection/models.py:755 +msgid "guide element sections" +msgstr "" + +#: apps/collection/models.py:966 +msgid "label photo" +msgstr "" + +#: apps/collection/models.py:975 +msgid "guide elements" +msgstr "" + +#: apps/collection/views/back.py:177 apps/collection/views/back.py:193 +#: apps/collection/views/back.py:209 apps/main/views/back.py:174 +#: apps/main/views/back.py:190 +msgid "The file will be sent to your email." +msgstr "" + +#: apps/comment/apps.py:7 apps/review/models.py:132 +msgid "comment" +msgstr "" + +#: apps/comment/apps.py:8 +msgid "comments" +msgstr "" + +#: apps/comment/models.py:64 apps/product/models.py:253 +#: apps/recipe/models.py:42 +msgid "Waiting" +msgstr "" + +#: apps/comment/models.py:65 apps/main/models.py:158 apps/product/models.py:251 +#: apps/recipe/models.py:44 +msgid "Published" +msgstr "" + +#: apps/comment/models.py:66 +msgid "Rejected" +msgstr "" + +#: apps/comment/models.py:67 +msgid "Deleted" +msgstr "" + +#: apps/comment/models.py:70 +msgid "Comment text" +msgstr "" + +#: apps/comment/models.py:73 +msgid "Mark" +msgstr "" + +#: apps/comment/models.py:79 +msgid "status" +msgstr "" + +#: apps/comment/models.py:90 +msgid "Comment" +msgstr "" + +#: apps/comment/models.py:91 +msgid "Comments" +msgstr "" + +#: apps/configuration/apps.py:7 +msgid "configuration" +msgstr "" + +#: apps/configuration/models.py:9 +msgid "default language" +msgstr "" + +#: apps/establishment/filters.py:126 apps/news/filters.py:55 +msgid "Type at least 3 characters to search please." +msgstr "" + +#: apps/establishment/models.py:50 apps/establishment/models.py:91 +#: apps/establishment/models.py:935 apps/recipe/models.py:53 +msgid "Description" +msgstr "" + +#: apps/establishment/models.py:53 apps/establishment/models.py:94 +#: apps/establishment/models.py:533 apps/establishment/models.py:941 +#: apps/notification/models.py:18 apps/product/models.py:51 +#: apps/product/models.py:89 +msgid "Index name" +msgstr "" + +#: apps/establishment/models.py:54 apps/product/models.py:52 +msgid "Use subtypes" +msgstr "" + +#: apps/establishment/models.py:58 apps/establishment/models.py:101 +#: apps/product/models.py:56 apps/tag/models.py:176 +msgid "Tag categories" +msgstr "" + +#: apps/establishment/models.py:67 +msgid "Establishment type" +msgstr "" + +#: apps/establishment/models.py:68 +msgid "Establishment types" +msgstr "" + +#: apps/establishment/models.py:97 apps/product/models.py:266 +msgid "Type" +msgstr "" + +#: apps/establishment/models.py:113 +msgid "Establishment subtypes" +msgstr "" + +#: apps/establishment/models.py:117 +msgid "Establishment type is not use subtypes." +msgstr "" + +#: apps/establishment/models.py:530 +msgid "Transliterated name" +msgstr "" + +#: apps/establishment/models.py:532 +msgid "Western name" +msgstr "" + +#: apps/establishment/models.py:539 apps/product/models.py:275 +msgid "public mark" +msgstr "" + +#: apps/establishment/models.py:543 +msgid "toque number" +msgstr "" + +#: apps/establishment/models.py:547 +msgid "type" +msgstr "" + +#: apps/establishment/models.py:551 +msgid "subtype" +msgstr "" + +#: apps/establishment/models.py:554 apps/establishment/models.py:1473 +#: apps/news/models.py:34 apps/news/models.py:315 +msgid "address" +msgstr "" + +#: apps/establishment/models.py:557 +msgid "price level" +msgstr "" + +#: apps/establishment/models.py:559 +msgid "Web site URL" +msgstr "" + +#: apps/establishment/models.py:561 +msgid "Facebook URL" +msgstr "" + +#: apps/establishment/models.py:563 +msgid "Twitter URL" +msgstr "" + +#: apps/establishment/models.py:565 +msgid "Instagram URL" +msgstr "" + +#: apps/establishment/models.py:567 +msgid "Lafourchette URL" +msgstr "" + +#: apps/establishment/models.py:568 +msgid "guestonline id" +msgstr "" + +#: apps/establishment/models.py:570 +msgid "lastable id" +msgstr "" + +#: apps/establishment/models.py:573 +msgid "Booking URL" +msgstr "" + +#: apps/establishment/models.py:576 apps/establishment/models.py:1285 +msgid "Establishment schedule" +msgstr "" + +#: apps/establishment/models.py:579 +msgid "Transportation" +msgstr "" + +#: apps/establishment/models.py:583 +msgid "Collections" +msgstr "" + +#: apps/establishment/models.py:585 +msgid "Preview image URL path" +msgstr "" + +#: apps/establishment/models.py:588 +msgid "Establishment slug" +msgstr "" + +#: apps/establishment/models.py:593 apps/product/models.py:296 +#: apps/product/models.py:591 apps/tag/models.py:65 +msgid "Tag" +msgstr "" + +#: apps/establishment/models.py:600 apps/establishment/models.py:1223 +#: apps/main/models.py:39 +msgid "currency" +msgstr "" + +#: apps/establishment/models.py:604 apps/product/models.py:483 +msgid "purchased plaques" +msgstr "" + +#: apps/establishment/models.py:605 +msgid "" +"Attribute from legacy db.\n" +"Must be deleted after the implementation of the market." +msgstr "" + +#: apps/establishment/models.py:615 +msgid "Establishments" +msgstr "" + +#: apps/establishment/models.py:896 apps/product/models.py:609 +#: apps/review/models.py:69 +msgid "text" +msgstr "" + +#: apps/establishment/models.py:899 apps/establishment/models.py:917 +#: apps/establishment/models.py:1279 apps/establishment/models.py:1356 +#: apps/establishment/models.py:1449 apps/product/models.py:273 +#: apps/product/models.py:472 +msgid "establishment" +msgstr "" + +#: apps/establishment/models.py:903 apps/product/models.py:616 +#: apps/review/models.py:103 apps/review/models.py:138 +msgid "author" +msgstr "" + +#: apps/establishment/models.py:909 +msgid "establishment notes" +msgstr "" + +#: apps/establishment/models.py:910 +msgid "establishment note" +msgstr "" + +#: apps/establishment/models.py:921 apps/establishment/models.py:1311 +#: apps/product/models.py:545 apps/review/models.py:188 +msgid "image" +msgstr "" + +#: apps/establishment/models.py:925 +msgid "establishment gallery" +msgstr "" + +#: apps/establishment/models.py:926 +msgid "establishment galleries" +msgstr "" + +#: apps/establishment/models.py:946 apps/establishment/models.py:983 +msgid "Position" +msgstr "" + +#: apps/establishment/models.py:947 +msgid "Positions" +msgstr "" + +#: apps/establishment/models.py:977 apps/establishment/models.py:1140 +msgid "Employee" +msgstr "" + +#: apps/establishment/models.py:978 +msgid "From date" +msgstr "" + +#: apps/establishment/models.py:981 +msgid "To date" +msgstr "" + +#: apps/establishment/models.py:988 apps/establishment/models.py:1128 +msgid "Old id" +msgstr "" + +#: apps/establishment/models.py:1102 +msgid "Last Name" +msgstr "" + +#: apps/establishment/models.py:1110 +msgid "Male" +msgstr "" + +#: apps/establishment/models.py:1111 +msgid "Female" +msgstr "" + +#: apps/establishment/models.py:1113 +msgid "Sex" +msgstr "" + +#: apps/establishment/models.py:1115 +msgid "Birth date" +msgstr "" + +#: apps/establishment/models.py:1117 apps/notification/models.py:106 +msgid "Email" +msgstr "" + +#: apps/establishment/models.py:1119 +msgid "Toque number" +msgstr "" + +#: apps/establishment/models.py:1126 apps/news/models.py:321 +#: apps/tag/models.py:66 +msgid "Tags" +msgstr "" + +#: apps/establishment/models.py:1129 +msgid "Available for events" +msgstr "" + +#: apps/establishment/models.py:1133 apps/location/models.py:170 +msgid "image instance of model Image" +msgstr "" + +#: apps/establishment/models.py:1141 +msgid "Employees" +msgstr "" + +#: apps/establishment/models.py:1188 +msgid "contact phone" +msgstr "" + +#: apps/establishment/models.py:1189 apps/establishment/models.py:1453 +msgid "contact phones" +msgstr "" + +#: apps/establishment/models.py:1202 +msgid "contact email" +msgstr "" + +#: apps/establishment/models.py:1203 +msgid "contact emails" +msgstr "" + +#: apps/establishment/models.py:1220 apps/review/models.py:141 +msgid "price" +msgstr "" + +#: apps/establishment/models.py:1221 +msgid "is signature plate" +msgstr "" + +#: apps/establishment/models.py:1226 +msgid "currency code" +msgstr "" + +#: apps/establishment/models.py:1230 apps/establishment/models.py:1293 +#: apps/establishment/models.py:1294 apps/establishment/models.py:1304 +#: apps/establishment/models.py:1326 +msgid "menu" +msgstr "" + +#: apps/establishment/models.py:1240 +msgid "plate" +msgstr "" + +#: apps/establishment/models.py:1241 +msgid "plates" +msgstr "" + +#: apps/establishment/models.py:1281 +msgid "is drinks included" +msgstr "" + +#: apps/establishment/models.py:1316 +msgid "menu gallery" +msgstr "" + +#: apps/establishment/models.py:1317 +msgid "menu galleries" +msgstr "" + +#: apps/establishment/models.py:1330 apps/establishment/models.py:1342 +#: apps/gallery/models.py:29 apps/main/models.py:196 apps/main/models.py:402 +#: apps/news/models.py:47 apps/news/models.py:287 +msgid "title" +msgstr "" + +#: apps/establishment/models.py:1332 +msgid "File" +msgstr "" + +#: apps/establishment/models.py:1337 +msgid "menu upload" +msgstr "" + +#: apps/establishment/models.py:1338 +msgid "menu uploads" +msgstr "" + +#: apps/establishment/models.py:1345 +msgid "social choice" +msgstr "" + +#: apps/establishment/models.py:1346 +msgid "social choices" +msgstr "" + +#: apps/establishment/models.py:1362 apps/establishment/models.py:1369 +msgid "social network" +msgstr "" + +#: apps/establishment/models.py:1366 +msgid "URL" +msgstr "" + +#: apps/establishment/models.py:1370 +msgid "social networks" +msgstr "" + +#: apps/establishment/models.py:1411 +msgid "One" +msgstr "" + +#: apps/establishment/models.py:1412 +msgid "Two" +msgstr "" + +#: apps/establishment/models.py:1413 +msgid "Three" +msgstr "" + +#: apps/establishment/models.py:1414 +msgid "Four" +msgstr "" + +#: apps/establishment/models.py:1415 +msgid "Five" +msgstr "" + +#: apps/establishment/models.py:1430 apps/establishment/models.py:1431 +msgid "Rating strategy" +msgstr "" + +#: apps/establishment/models.py:1456 +msgid "fax numbers" +msgstr "" + +#: apps/establishment/models.py:1459 +msgid "legal entity" +msgstr "" + +#: apps/establishment/models.py:1462 +msgid "registry number" +msgstr "" + +#: apps/establishment/models.py:1465 +msgid "VAT identification number" +msgstr "" + +#: apps/establishment/models.py:1469 +msgid "sic code" +msgstr "" + +#: apps/establishment/models.py:1479 +msgid "company" +msgstr "" + +#: apps/establishment/models.py:1480 +msgid "companies" +msgstr "" + +#: apps/establishment/serializers/back.py:467 +msgid "Establishment not found" +msgstr "" + +#: apps/establishment/serializers/back.py:470 +#: apps/establishment/serializers/back.py:680 apps/news/serializers.py:445 +#: apps/product/serializers/back.py:42 +msgid "Image not found" +msgstr "" + +#: apps/establishment/serializers/back.py:476 +#: apps/product/serializers/back.py:48 +msgid "Image is already added." +msgstr "" + +#: apps/establishment/serializers/back.py:678 +msgid "Menu not found" +msgstr "" + +#: apps/establishment/serializers/common.py:212 +#, python-brace-format +msgid "{entity_class.__name__} not found." +msgstr "" + +#: apps/establishment/serializers/common.py:547 +#: apps/timetable/serialziers.py:61 +msgid "Establishment not found." +msgstr "" + +#: apps/establishment/serializers/common.py:586 +#: apps/establishment/serializers/common.py:614 apps/news/serializers.py:469 +#: apps/news/serializers.py:495 apps/product/serializers/common.py:183 +msgid "Object not found." +msgstr "" + +#: apps/establishment/serializers/common.py:675 +msgid "Fax is already reserved." +msgstr "" + +#: apps/establishment/serializers/common.py:679 +msgid "Phones is already reserved." +msgstr "" + +#: apps/favorites/apps.py:7 apps/favorites/models.py:32 +#: apps/favorites/models.py:33 +msgid "Favorites" +msgstr "" + +#: apps/gallery/apps.py:7 apps/news/models.py:495 +msgid "gallery" +msgstr "" + +#: apps/gallery/models.py:20 +msgid "Horizontal" +msgstr "" + +#: apps/gallery/models.py:21 +msgid "Vertical" +msgstr "" + +#: apps/gallery/models.py:25 +msgid "image file" +msgstr "" + +#: apps/gallery/models.py:28 +msgid "image orientation" +msgstr "" + +#: apps/gallery/models.py:35 apps/utils/models.py:169 apps/utils/models.py:198 +#: apps/utils/models.py:207 apps/utils/models.py:248 apps/utils/models.py:283 +msgid "Image" +msgstr "" + +#: apps/gallery/models.py:36 +msgid "Images" +msgstr "" + +#: apps/gallery/serializers.py:43 +#, python-format +msgid "File size too large: %s bytes" +msgstr "" + +#: apps/gallery/serializers.py:92 +#, python-format +msgid "Unrecognized crop option: %s" +msgstr "" + +#: apps/gallery/serializers.py:139 +msgid "Image not found." +msgstr "" + +#: apps/location/admin.py:28 apps/main/apps.py:8 apps/main/models.py:161 +msgid "Main" +msgstr "" + +#: apps/location/admin.py:31 +msgid "Location" +msgstr "" + +#: apps/location/admin.py:34 +msgid "Address detail" +msgstr "" + +#: apps/location/apps.py:7 +msgid "location" +msgstr "" + +#: apps/location/models.py:42 +msgid "Code" +msgstr "" + +#: apps/location/models.py:43 +msgid "Low price" +msgstr "" + +#: apps/location/models.py:44 +msgid "High price" +msgstr "" + +#: apps/location/models.py:45 apps/translation/models.py:43 +msgid "Languages" +msgstr "" + +#: apps/location/models.py:46 apps/translation/models.py:35 +msgid "is active" +msgstr "" + +#: apps/location/models.py:56 +msgid "Countries" +msgstr "" + +#: apps/location/models.py:102 apps/location/models.py:150 +msgid "code" +msgstr "" + +#: apps/location/models.py:104 apps/location/models.py:153 +msgid "parent region" +msgstr "" + +#: apps/location/models.py:116 +msgid "regions" +msgstr "" + +#: apps/location/models.py:117 +msgid "region" +msgstr "" + +#: apps/location/models.py:149 +msgid "City name json" +msgstr "" + +#: apps/location/models.py:158 apps/location/models.py:222 +msgid "postal code" +msgstr "" + +#: apps/location/models.py:158 apps/location/models.py:223 +msgid "Ex.: 350018" +msgstr "" + +#: apps/location/models.py:160 +msgid "is island" +msgstr "" + +#: apps/location/models.py:177 +msgid "cities" +msgstr "" + +#: apps/location/models.py:178 apps/location/models.py:215 +msgid "city" +msgstr "" + +#: apps/location/models.py:217 +msgid "street name 1" +msgstr "" + +#: apps/location/models.py:219 +msgid "street name 2" +msgstr "" + +#: apps/location/models.py:220 +msgid "number" +msgstr "" + +#: apps/location/models.py:225 apps/location/models.py:285 +#: apps/product/models.py:525 +msgid "Coordinates" +msgstr "" + +#: apps/location/models.py:227 +msgid "District name" +msgstr "" + +#: apps/location/models.py:233 apps/location/models.py:234 +msgid "Address" +msgstr "" + +#: apps/location/models.py:299 +msgid "wine regions" +msgstr "" + +#: apps/location/models.py:300 apps/location/models.py:343 +#: apps/location/models.py:362 +msgid "wine region" +msgstr "" + +#: apps/location/models.py:316 apps/location/models.py:325 +#: apps/location/models.py:365 +msgid "wine sub region" +msgstr "" + +#: apps/location/models.py:324 +msgid "wine sub regions" +msgstr "" + +#: apps/location/models.py:351 apps/product/models.py:285 +msgid "wine village" +msgstr "" + +#: apps/location/models.py:352 +msgid "wine villages" +msgstr "" + +#: apps/location/models.py:380 apps/location/models.py:398 +#: apps/product/models.py:541 apps/product/models.py:612 +msgid "product" +msgstr "" + +#: apps/location/models.py:386 +msgid "establishment wine origin address" +msgstr "" + +#: apps/location/models.py:387 +msgid "establishment wine origin addresses" +msgstr "" + +#: apps/location/models.py:404 +msgid "wine origin address" +msgstr "" + +#: apps/location/models.py:405 +msgid "wine origin addresses" +msgstr "" + +#: apps/location/serializers/common.py:184 +#: apps/location/serializers/common.py:189 +msgid "Invalid value" +msgstr "" + +#: apps/main/models.py:34 +msgid "sign" +msgstr "" + +#: apps/main/models.py:40 +msgid "currencies" +msgstr "" + +#: apps/main/models.py:58 +msgid "Subdomain" +msgstr "" + +#: apps/main/models.py:63 +msgid "Default site" +msgstr "" + +#: apps/main/models.py:65 +msgid "Pinterest page URL" +msgstr "" + +#: apps/main/models.py:67 +msgid "Twitter page URL" +msgstr "" + +#: apps/main/models.py:69 +msgid "Facebook page URL" +msgstr "" + +#: apps/main/models.py:71 +msgid "Instagram page URL" +msgstr "" + +#: apps/main/models.py:73 +msgid "Contact email" +msgstr "" + +#: apps/main/models.py:75 +msgid "Config" +msgstr "" + +#: apps/main/models.py:77 +msgid "AD config" +msgstr "" + +#: apps/main/models.py:87 +msgid "Site setting" +msgstr "" + +#: apps/main/models.py:128 +msgid "Feature" +msgstr "" + +#: apps/main/models.py:129 +msgid "Features" +msgstr "" + +#: apps/main/models.py:164 +msgid "backoffice" +msgstr "" + +#: apps/main/models.py:173 +msgid "Site feature" +msgstr "" + +#: apps/main/models.py:174 +msgid "Site features" +msgstr "" + +#: apps/main/models.py:198 apps/product/models.py:300 +msgid "vintage year" +msgstr "" + +#: apps/main/models.py:205 apps/news/models.py:310 apps/recipe/models.py:55 +msgid "State" +msgstr "" + +#: apps/main/models.py:257 +msgid "is international" +msgstr "" + +#: apps/main/models.py:259 +msgid "old title" +msgstr "" + +#: apps/main/models.py:260 +msgid "old link" +msgstr "" + +#: apps/main/models.py:261 +msgid "old attachment_suffix_url" +msgstr "" + +#: apps/main/models.py:262 +msgid "old description" +msgstr "" + +#: apps/main/models.py:263 +msgid "old link_title" +msgstr "" + +#: apps/main/models.py:271 +msgid "old active" +msgstr "" + +#: apps/main/models.py:272 +msgid "is parse" +msgstr "" + +#: apps/main/models.py:278 apps/main/models.py:279 +msgid "Carousel" +msgstr "" + +#: apps/main/models.py:361 +msgid "Block width" +msgstr "" + +#: apps/main/models.py:363 +msgid "Block height" +msgstr "" + +#: apps/main/models.py:369 +msgid "page" +msgstr "" + +#: apps/main/models.py:370 +msgid "pages" +msgstr "" + +#: apps/main/models.py:393 +msgid "page types" +msgstr "" + +#: apps/main/models.py:401 +msgid "link" +msgstr "" + +#: apps/main/models.py:407 +msgid "footer" +msgstr "" + +#: apps/main/models.py:410 +msgid "about_us" +msgstr "" + +#: apps/main/models.py:411 +msgid "copyright" +msgstr "" + +#: apps/main/models.py:412 +msgid "links" +msgstr "" + +#: apps/main/models.py:425 +msgid "table" +msgstr "" + +#: apps/main/models.py:426 +msgid "mailing" +msgstr "" + +#: apps/main/models.py:430 +msgid "display" +msgstr "" + +#: apps/main/models.py:435 +msgid "query" +msgstr "" + +#: apps/main/models.py:437 +msgid "user" +msgstr "" + +#: apps/main/models.py:448 +msgid "panel" +msgstr "" + +#: apps/main/models.py:449 +msgid "panels" +msgstr "" + +#: apps/main/models.py:557 +msgid "read" +msgstr "" + +#: apps/main/models.py:558 +msgid "write" +msgstr "" + +#: apps/main/models.py:562 +msgid "sections" +msgstr "" + +#: apps/main/models.py:568 +msgid "permission mode" +msgstr "" + +#: apps/main/models.py:572 +msgid "Navigation bar item permission" +msgstr "" + +#: apps/main/models.py:573 +msgid "Navigation bar item permissions" +msgstr "" + +#: apps/news/apps.py:7 apps/news/models.py:346 apps/news/models.py:347 +#: apps/news/models.py:491 +msgid "news" +msgstr "" + +#: apps/news/filters.py:17 apps/recipe/models.py:70 +msgid "Recipes" +msgstr "" + +#: apps/news/models.py:30 +msgid "Start datetime" +msgstr "" + +#: apps/news/models.py:32 +msgid "End datetime" +msgstr "" + +#: apps/news/models.py:37 +msgid "event name" +msgstr "" + +#: apps/news/models.py:40 +msgid "content" +msgstr "" + +#: apps/news/models.py:51 +msgid "Content URL path" +msgstr "" + +#: apps/news/models.py:78 +msgid "news types" +msgstr "" + +#: apps/news/models.py:79 apps/news/models.py:285 +msgid "news type" +msgstr "" + +#: apps/news/models.py:274 +msgid "remove" +msgstr "supprimé" + +#: apps/news/models.py:275 +msgid "hidden" +msgstr "caché" + +#: apps/news/models.py:276 +msgid "published" +msgstr "publié" + +#: apps/news/models.py:277 +msgid "not published" +msgstr "non publié" + +#: apps/news/models.py:290 +msgid "Title for searching via BO" +msgstr "" + +#: apps/news/models.py:292 +msgid "subtitle" +msgstr "" + +#: apps/news/models.py:298 +msgid "Is description for certain locale active" +msgstr "" + +#: apps/news/models.py:300 +msgid "News publication date" +msgstr "" + +#: apps/news/models.py:301 +msgid "date since when news item is published" +msgstr "" + +#: apps/news/models.py:302 +msgid "News publication time" +msgstr "" + +#: apps/news/models.py:303 +msgid "time since when news item is published" +msgstr "" + +#: apps/news/models.py:305 +msgid "End" +msgstr "" + +#: apps/news/models.py:307 +msgid "Slugs for current news obj" +msgstr "" + +#: apps/news/models.py:312 +msgid "Is highlighted" +msgstr "" + +#: apps/news/models.py:330 +msgid "agenda" +msgstr "" + +#: apps/news/models.py:334 +msgid "banner" +msgstr "" + +#: apps/news/models.py:338 +msgid "Duplication datetime" +msgstr "" + +#: apps/news/models.py:340 +msgid "Field to detect doubles" +msgstr "" + +#: apps/news/models.py:499 +msgid "news gallery" +msgstr "" + +#: apps/news/models.py:500 +msgid "news galleries" +msgstr "" + +#: apps/news/serializers.py:276 apps/news/serializers.py:308 +msgid "Slug should be unique" +msgstr "" + +#: apps/news/serializers.py:443 +msgid "News not found" +msgstr "" + +#: apps/notification/apps.py:7 +msgid "notification" +msgstr "" + +#: apps/notification/models.py:107 +msgid "IP address" +msgstr "" + +#: apps/notification/models.py:108 +msgid "Country code" +msgstr "" + +#: apps/notification/models.py:109 apps/translation/models.py:31 +msgid "Locale identifier" +msgstr "" + +#: apps/notification/models.py:116 +msgid "Token" +msgstr "" + +#: apps/notification/models.py:127 +msgid "Subscriber" +msgstr "" + +#: apps/notification/models.py:128 +msgid "Subscribers" +msgstr "" + +#: apps/notification/models.py:190 +msgid "Last unsubscribe date" +msgstr "" + +#: apps/notification/models.py:195 +msgid "Old subscriber id" +msgstr "" + +#: apps/notification/models.py:196 +msgid "Old subscription type id" +msgstr "" + +#: apps/notification/models.py:207 +msgid "Subscribe" +msgstr "" + +#: apps/notification/models.py:208 +msgid "Subscribes" +msgstr "" + +#: apps/notification/serializers/common.py:65 +msgid "Does not match user email" +msgstr "" + +#: apps/notification/serializers/common.py:68 +msgid "This field is required." +msgstr "" + +#: apps/notification/tasks.py:31 +msgid "You have subscribed on news G&M" +msgstr "" + +#: apps/notification/tasks.py:32 +msgid "
" +msgstr "" + +#: apps/notification/tasks.py:46 +msgid "G&M Subscriptions" +msgstr "" + +#: apps/notification/tasks.py:73 +msgid "You have successfully unsubscribed from G&M news" +msgstr "" + +#: apps/partner/apps.py:7 apps/partner/models.py:36 +msgid "partner" +msgstr "" + +#: apps/partner/models.py:14 +msgid "Partner" +msgstr "" + +#: apps/partner/models.py:15 +msgid "Sponsor" +msgstr "" + +#: apps/partner/models.py:20 +msgid "Partner URL" +msgstr "" + +#: apps/partner/models.py:21 +msgid "Partner image URL" +msgstr "" + +#: apps/partner/models.py:31 +msgid "starting date" +msgstr "" + +#: apps/partner/models.py:32 +msgid "expiry date" +msgstr "" + +#: apps/partner/models.py:33 +msgid "price per month" +msgstr "" + +#: apps/partner/models.py:37 +msgid "partners" +msgstr "" + +#: apps/product/apps.py:7 apps/product/models.py:323 +msgid "Product" +msgstr "" + +#: apps/product/models.py:65 apps/product/models.py:85 +msgid "Product type" +msgstr "" + +#: apps/product/models.py:66 +msgid "Product types" +msgstr "" + +#: apps/product/models.py:98 +msgid "Product subtype" +msgstr "" + +#: apps/product/models.py:99 +msgid "Product subtypes" +msgstr "" + +#: apps/product/models.py:103 +msgid "Product type is not use subtypes." +msgstr "" + +#: apps/product/models.py:242 +msgid "Common" +msgstr "" + +#: apps/product/models.py:243 +msgid "Online" +msgstr "" + +#: apps/product/models.py:252 +msgid "Out_of_production" +msgstr "" + +#: apps/product/models.py:263 +msgid "available" +msgstr "" + +#: apps/product/models.py:269 +msgid "Subtypes" +msgstr "" + +#: apps/product/models.py:278 +msgid "classifications" +msgstr "" + +#: apps/product/models.py:281 +msgid "standards" +msgstr "" + +#: apps/product/models.py:282 apps/product/models.py:294 +#: apps/product/models.py:299 +msgid "attribute from legacy db" +msgstr "" + +#: apps/product/models.py:287 apps/recipe/models.py:62 +msgid "Slug" +msgstr "" + +#: apps/product/models.py:306 +msgid "average price" +msgstr "" + +#: apps/product/models.py:314 +msgid "Serial number" +msgstr "" + +#: apps/product/models.py:324 +msgid "Products" +msgstr "" + +#: apps/product/models.py:463 +msgid "Online product" +msgstr "" + +#: apps/product/models.py:464 +msgid "Online products" +msgstr "" + +#: apps/product/models.py:475 +msgid "plaque" +msgstr "" + +#: apps/product/models.py:477 +msgid "is gifted" +msgstr "" + +#: apps/product/models.py:478 +msgid "quantity" +msgstr "" + +#: apps/product/models.py:482 +msgid "purchased plaque" +msgstr "" + +#: apps/product/models.py:492 apps/review/models.py:162 +msgid "value" +msgstr "" + +#: apps/product/models.py:496 +msgid "unit" +msgstr "" + +#: apps/product/models.py:497 +msgid "units" +msgstr "" + +#: apps/product/models.py:516 +msgid "Appellation" +msgstr "" + +#: apps/product/models.py:517 +msgid "Wine quality" +msgstr "" + +#: apps/product/models.py:518 +msgid "Yard classification" +msgstr "" + +#: apps/product/models.py:523 +msgid "standard type" +msgstr "" + +#: apps/product/models.py:532 +msgid "wine standards" +msgstr "" + +#: apps/product/models.py:533 +msgid "wine standard" +msgstr "" + +#: apps/product/models.py:549 +msgid "product gallery" +msgstr "" + +#: apps/product/models.py:550 +msgid "product galleries" +msgstr "" + +#: apps/product/models.py:558 apps/product/models.py:586 +msgid "classification type" +msgstr "" + +#: apps/product/models.py:561 +msgid "product type" +msgstr "" + +#: apps/product/models.py:564 +msgid "product subtype" +msgstr "" + +#: apps/product/models.py:565 +msgid "" +"Legacy attribute - possible_type (product type).Product type in our case is " +"product subtype." +msgstr "" + +#: apps/product/models.py:570 +msgid "wine classification type" +msgstr "" + +#: apps/product/models.py:571 +msgid "wine classification types" +msgstr "" + +#: apps/product/models.py:589 +msgid "standard" +msgstr "" + +#: apps/product/models.py:598 +msgid "product classification" +msgstr "" + +#: apps/product/models.py:599 +msgid "product classifications" +msgstr "" + +#: apps/product/models.py:622 +msgid "product note" +msgstr "" + +#: apps/product/models.py:623 +msgid "product notes" +msgstr "" + +#: apps/product/serializers/back.py:39 +msgid "Product not found" +msgstr "" + +#: apps/product/serializers/back.py:110 +msgid "Tag category is already attached." +msgstr "" + +#: apps/product/serializers/common.py:229 +msgid "Product not found." +msgstr "" + +#: apps/rating/models.py:11 +msgid "ip" +msgstr "" + +#: apps/recipe/apps.py:8 +msgid "RecipeConfig" +msgstr "" + +#: apps/recipe/models.py:43 +msgid "Hidden" +msgstr "" + +#: apps/recipe/models.py:45 +msgid "Published exclusive" +msgstr "" + +#: apps/recipe/models.py:50 +msgid "Title" +msgstr "" + +#: apps/recipe/models.py:51 +msgid "Subtitle" +msgstr "" + +#: apps/recipe/models.py:56 +msgid "Author" +msgstr "" + +#: apps/recipe/models.py:57 apps/recipe/models.py:58 +msgid "Published at" +msgstr "" + +#: apps/recipe/models.py:59 apps/recipe/models.py:60 +msgid "Published scheduled at" +msgstr "" + +#: apps/recipe/models.py:69 +msgid "Recipe" +msgstr "" + +#: apps/review/apps.py:7 +msgid "reviews" +msgstr "" + +#: apps/review/models.py:42 +msgid "To investigate" +msgstr "" + +#: apps/review/models.py:43 +msgid "To review" +msgstr "" + +#: apps/review/models.py:44 +msgid "Ready" +msgstr "" + +#: apps/review/models.py:50 +msgid "Reviewer" +msgstr "" + +#: apps/review/models.py:66 +msgid "Child review" +msgstr "" + +#: apps/review/models.py:81 +msgid "Publish datetime" +msgstr "" + +#: apps/review/models.py:85 +msgid "Review published datetime" +msgstr "" + +#: apps/review/models.py:87 +msgid "Year of review" +msgstr "" + +#: apps/review/models.py:88 apps/review/models.py:134 +msgid "mark" +msgstr "" + +#: apps/review/models.py:89 +msgid "Priority" +msgstr "" + +#: apps/review/models.py:96 +msgid "Review" +msgstr "" + +#: apps/review/models.py:97 +msgid "Reviews" +msgstr "" + +#: apps/review/models.py:109 apps/review/models.py:131 +msgid "review" +msgstr "" + +#: apps/review/models.py:113 +msgid "locale" +msgstr "" + +#: apps/review/models.py:116 +msgid "Text author" +msgstr "" + +#: apps/review/models.py:117 +msgid "Text authors" +msgstr "" + +#: apps/review/models.py:126 +msgid "none" +msgstr "" + +#: apps/review/models.py:127 +msgid "diner" +msgstr "" + +#: apps/review/models.py:128 +msgid "lanch" +msgstr "" + +#: apps/review/models.py:133 +msgid "final comment" +msgstr "" + +#: apps/review/models.py:135 +msgid "attachment" +msgstr "" + +#: apps/review/models.py:139 +msgid "bill" +msgstr "" + +#: apps/review/models.py:147 +msgid "is published" +msgstr "" + +#: apps/review/models.py:150 +msgid "Inquiry" +msgstr "" + +#: apps/review/models.py:151 +msgid "Inquiries" +msgstr "" + +#: apps/review/models.py:159 apps/review/models.py:181 +msgid "inquiry" +msgstr "" + +#: apps/review/models.py:160 +msgid "sub name" +msgstr "" + +#: apps/review/models.py:164 +msgid "dish title" +msgstr "" + +#: apps/review/models.py:167 +msgid "inquiry grid" +msgstr "" + +#: apps/review/models.py:168 +msgid "inquiry grids" +msgstr "" + +#: apps/review/models.py:192 +msgid "inquiry gallery" +msgstr "" + +#: apps/review/models.py:193 +msgid "inquiry galleries" +msgstr "" + +#: apps/search_indexes/apps.py:7 +msgid "Search indexes" +msgstr "" + +#: apps/tag/apps.py:7 apps/tag/models.py:185 +msgid "tag" +msgstr "" + +#: apps/tag/models.py:36 apps/tag/models.py:153 +msgid "indexing name" +msgstr "" + +#: apps/tag/models.py:40 +msgid "Category" +msgstr "" + +#: apps/tag/models.py:47 +msgid "old id metadata product" +msgstr "" + +#: apps/tag/models.py:50 apps/tag/models.py:160 apps/translation/apps.py:7 +msgid "Translation" +msgstr "" + +#: apps/tag/models.py:90 +msgid "Chosen tag" +msgstr "" + +#: apps/tag/models.py:91 +msgid "Chosen tags" +msgstr "" + +#: apps/tag/models.py:141 +msgid "string" +msgstr "" + +#: apps/tag/models.py:142 +msgid "list" +msgstr "" + +#: apps/tag/models.py:143 +msgid "integer" +msgstr "" + +#: apps/tag/models.py:144 +msgid "float" +msgstr "" + +#: apps/tag/models.py:145 +msgid "percentage" +msgstr "" + +#: apps/tag/models.py:146 +msgid "boolean" +msgstr "" + +#: apps/tag/models.py:155 +msgid "value type" +msgstr "" + +#: apps/tag/models.py:175 +msgid "Tag category" +msgstr "" + +#: apps/tag/views.py:234 +msgid "Missing required \"items\" parameter" +msgstr "" + +#: apps/tag/views.py:242 +msgid "news/establishments/products" +msgstr "" + +#: apps/timetable/apps.py:7 +msgid "timetable" +msgstr "" + +#: apps/timetable/models.py:22 +msgid "Monday" +msgstr "" + +#: apps/timetable/models.py:23 +msgid "Tuesday" +msgstr "" + +#: apps/timetable/models.py:24 +msgid "Wednesday" +msgstr "" + +#: apps/timetable/models.py:25 +msgid "Thursday" +msgstr "" + +#: apps/timetable/models.py:26 +msgid "Friday" +msgstr "" + +#: apps/timetable/models.py:27 +msgid "Saturday" +msgstr "" + +#: apps/timetable/models.py:28 +msgid "Sunday" +msgstr "" + +#: apps/timetable/models.py:31 +msgid "Week day" +msgstr "" + +#: apps/timetable/models.py:33 +msgid "Lunch start time" +msgstr "" + +#: apps/timetable/models.py:34 +msgid "Lunch end time" +msgstr "" + +#: apps/timetable/models.py:35 +msgid "Dinner start time" +msgstr "" + +#: apps/timetable/models.py:36 +msgid "Dinner end time" +msgstr "" + +#: apps/timetable/models.py:37 +msgid "Opening time" +msgstr "" + +#: apps/timetable/models.py:38 +msgid "Closed time" +msgstr "" + +#: apps/timetable/models.py:42 +msgid "Timetable" +msgstr "" + +#: apps/timetable/models.py:43 +msgid "Timetables" +msgstr "" + +#: apps/transfer/apps.py:7 +msgid "Transfer" +msgstr "" + +#: apps/translation/models.py:29 +msgid "Language title" +msgstr "" + +#: apps/translation/models.py:42 +msgid "Language" +msgstr "" + +#: apps/translation/models.py:97 +msgid "Page" +msgstr "" + +#: apps/translation/models.py:99 +msgid "Text" +msgstr "" + +#: apps/translation/models.py:107 apps/translation/models.py:108 +msgid "Site interface dictionary" +msgstr "" + +#: apps/utils/exceptions.py:8 +msgid "Bad request" +msgstr "" + +#: apps/utils/exceptions.py:27 +msgid "Service is temporarily unavailable" +msgstr "" + +#: apps/utils/exceptions.py:32 +msgid "User not found" +msgstr "" + +#: apps/utils/exceptions.py:38 +#, python-format +msgid "Unable to send message to mailbox %s" +msgstr "" + +#: apps/utils/exceptions.py:53 +#, python-format +msgid "Locale not found in database (%s)" +msgstr "" + +#: apps/utils/exceptions.py:68 +msgid "Wrong username" +msgstr "" + +#: apps/utils/exceptions.py:76 +msgid "Not valid token" +msgstr "" + +#: apps/utils/exceptions.py:83 +msgid "Not valid access token" +msgstr "" + +#: apps/utils/exceptions.py:90 +msgid "Not valid refresh token" +msgstr "" + +#: apps/utils/exceptions.py:95 +msgid "OAuth2 Error" +msgstr "" + +#: apps/utils/exceptions.py:111 +msgid "Email address is already confirmed" +msgstr "" + +#: apps/utils/exceptions.py:119 +msgid "Image invalid input." +msgstr "" + +#: apps/utils/exceptions.py:126 +msgid "Incorrect login or password." +msgstr "" + +#: apps/utils/exceptions.py:135 +msgid "Item is already in favorites." +msgstr "" + +#: apps/utils/exceptions.py:143 +msgid "Item is already in carousels." +msgstr "" + +#: apps/utils/exceptions.py:152 +msgid "Password reset request is already exists and valid." +msgstr "" + +#: apps/utils/exceptions.py:161 +msgid "Object has already been added." +msgstr "" + +#: apps/utils/exceptions.py:167 +msgid "Binding object not found." +msgstr "" + +#: apps/utils/exceptions.py:173 +msgid "Removed binding object not found." +msgstr "" + +#: apps/utils/exceptions.py:181 +msgid "Unprocessable entity valid." +msgstr "" + +#: apps/utils/exceptions.py:190 +msgid "Guide element not valid for Guide." +msgstr "" + +#: apps/utils/exceptions.py:199 +msgid "Advertorial already exists for this guide element." +msgstr "" + +#: apps/utils/models.py:29 +msgid "Date created" +msgstr "" + +#: apps/utils/models.py:31 +msgid "Date updated" +msgstr "" + +#: apps/utils/models.py:148 +msgid "created by" +msgstr "" + +#: apps/utils/models.py:152 +msgid "modified by" +msgstr "" + +#: apps/utils/models.py:258 +msgid "SVG image" +msgstr "" + +#: apps/utils/models.py:295 +msgid "Mobile" +msgstr "" + +#: apps/utils/models.py:296 +msgid "Web" +msgstr "" + +#: apps/utils/models.py:297 +msgid "All" +msgstr "" + +#: apps/utils/models.py:300 +msgid "Source" +msgstr "" + +#: apps/utils/models.py:427 +msgid "Is the main image" +msgstr "" + #: project/templates/account/change_email.html:33 #, python-format msgid "" diff --git a/project/locale/ru/LC_MESSAGES/django.mo b/project/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..c90e51f2e2979e803403ecc8744353004e93545d GIT binary patch literal 888 zcmZ{gO;6NN6o#v!#_?m}%7rG!1w>*xPDf0zOb04caAM~p!$5+&La(K!^iFO&s0jlZ$OlUj{twb#cfPn8h8Ez*ZST;n2ny~$vO8u=e#}X_v-`iG{i-46STo)umM!; z0HyDOOW+&00Dge0;3rV}FQD|_;L91*U=;P&vzm4T`N}zfJcxV?xrnUvCh|4p5E(0{ zp}f>hDqztIjA-YBSz^An6#71kwV0>W zITibrV9R`kX-&bO!%DCE`WzEU$YYb5_T&?L+Mzk8HB)WWb1l~4BGqe25c>L~Zjk70 zZc?t<&|7RJR6BabOPNXYj@{C04ZUL1=h>bIqtL zyhxwoVmUD>?)09CH8MuWrFADBGzykw(9jU6vT)ln3>v2bVI1$WRXk~xtPxfAHVP%9 zNUN*ID`jJ37%Rr#70W89R&TCsJ?O7L96r_Ii_e^Vvt+?xoQg2GKRlMx\n" "Language-Team: LANGUAGE \n" @@ -20,24 +20,25 @@ msgstr "" "%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" "%100>=11 && n%100<=14)? 2 : 3);\n" -#: apps/account/admin.py:30 +#: apps/account/admin.py:32 msgid "Personal info" msgstr "" -#: apps/account/admin.py:34 +#: apps/account/admin.py:36 msgid "Subscription" msgstr "" -#: apps/account/admin.py:39 +#: apps/account/admin.py:41 msgid "Important dates" msgstr "" -#: apps/account/admin.py:40 +#: apps/account/admin.py:42 msgid "Permissions" msgstr "" -#: apps/account/admin.py:59 apps/location/models.py:18 -#: venv/lib/python3.6/site-packages/fcm_django/models.py:14 +#: apps/account/admin.py:61 apps/establishment/models.py:1101 +#: apps/location/models.py:41 apps/product/models.py:49 +#: apps/product/models.py:87 msgid "Name" msgstr "" @@ -54,7 +55,6 @@ msgid "Password already in use." msgstr "" #: apps/account/forms.py:19 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_form.html:50 msgid "New password" msgstr "" @@ -62,89 +62,247 @@ msgstr "" msgid "New password confirmation" msgstr "" -#: apps/account/models.py:31 apps/account/models.py:227 +#: apps/account/models.py:56 +msgid "Standard user" +msgstr "" + +#: apps/account/models.py:57 +msgid "Comments moderator" +msgstr "" + +#: apps/account/models.py:58 +msgid "Country admin" +msgstr "" + +#: apps/account/models.py:59 +msgid "Content page manager" +msgstr "" + +#: apps/account/models.py:60 +msgid "Establishment manager" +msgstr "" + +#: apps/account/models.py:61 +msgid "Reviewer manager" +msgstr "" + +#: apps/account/models.py:62 +msgid "Restaurant reviewer" +msgstr "" + +#: apps/account/models.py:63 +msgid "Sales man" +msgstr "" + +#: apps/account/models.py:64 +msgid "Winery reviewer" +msgstr "" + +#: apps/account/models.py:65 +msgid "Seller" +msgstr "" + +#: apps/account/models.py:66 +msgid "Liquor reviewer" +msgstr "" + +#: apps/account/models.py:67 +msgid "Product reviewer" +msgstr "" + +#: apps/account/models.py:70 apps/account/models.py:501 msgid "Role" msgstr "" -#: apps/account/models.py:33 apps/location/models.py:28 apps/main/models.py:117 +#: apps/account/models.py:72 apps/establishment/models.py:1420 +#: apps/location/models.py:57 apps/main/models.py:61 apps/review/models.py:57 msgid "Country" msgstr "" -#: apps/account/models.py:76 apps/news/models.py:126 apps/utils/models.py:194 -msgid "Image URL path" +#: apps/account/models.py:74 apps/main/models.py:88 +msgid "Site settings" msgstr "" -#: apps/account/models.py:78 -msgid "Cropped image URL path" -msgstr "" - -#: apps/account/models.py:80 -msgid "email address" -msgstr "" - -#: apps/account/models.py:82 -msgid "unconfirmed email" +#: apps/account/models.py:77 apps/establishment/models.py:112 +msgid "Establishment subtype" msgstr "" #: apps/account/models.py:83 +msgid "navigation bar permission" +msgstr "" + +#: apps/account/models.py:207 +msgid "username" +msgstr "" + +#: apps/account/models.py:210 +msgid "Required. 150 characters or fewer. Letters, digits and ./+/-/_ only." +msgstr "" + +#: apps/account/models.py:212 +msgid "A user with that username already exists." +msgstr "" + +#: apps/account/models.py:215 apps/news/models.py:49 apps/utils/models.py:270 +msgid "Image URL path" +msgstr "" + +#: apps/account/models.py:218 +msgid "Cropped image URL path" +msgstr "" + +#: apps/account/models.py:220 +msgid "email address" +msgstr "" + +#: apps/account/models.py:222 +msgid "unconfirmed email" +msgstr "" + +#: apps/account/models.py:223 msgid "email status" msgstr "" -#: apps/account/models.py:90 +#: apps/account/models.py:227 +msgid "User last used locale" +msgstr "" + +#: apps/account/models.py:229 +msgid "User last visited from city" +msgstr "" + +#: apps/account/models.py:230 +msgid "last IP address" +msgstr "" + +#: apps/account/models.py:233 +msgid "last site settings" +msgstr "" + +#: apps/account/models.py:240 +msgid "Phone" +msgstr "" + +#: apps/account/models.py:247 msgid "Roles" msgstr "" -#: apps/account/models.py:95 apps/account/models.py:226 -#: apps/comment/models.py:38 apps/establishment/models.py:435 -#: apps/favorites/models.py:23 apps/notification/models.py:79 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/object_history.html:30 +#: apps/account/models.py:253 apps/account/models.py:499 +#: apps/comment/models.py:74 apps/establishment/models.py:1100 +#: apps/favorites/models.py:23 apps/notification/models.py:104 msgid "User" msgstr "" -#: apps/account/models.py:96 +#: apps/account/models.py:254 msgid "Users" msgstr "" -#: apps/account/serializers/common.py:121 +#: apps/account/models.py:492 +msgid "validated" +msgstr "" + +#: apps/account/models.py:493 +msgid "pending" +msgstr "" + +#: apps/account/models.py:494 +msgid "cancelled" +msgstr "" + +#: apps/account/models.py:495 +msgid "rejected" +msgstr "" + +#: apps/account/models.py:503 apps/establishment/apps.py:8 +#: apps/establishment/models.py:614 apps/establishment/models.py:975 +#: apps/partner/models.py:24 +msgid "Establishment" +msgstr "" + +#: apps/account/models.py:507 apps/collection/models.py:280 +#: apps/product/models.py:293 +msgid "state" +msgstr "" + +#: apps/account/models.py:521 +msgid "New role" +msgstr "" + +#: apps/account/models.py:522 +msgid "Old role" +msgstr "" + +#: apps/account/serializers/common.py:226 msgid "Old password mismatch." msgstr "" -#: apps/account/serializers/common.py:124 apps/utils/exceptions.py:103 +#: apps/account/serializers/common.py:229 apps/utils/exceptions.py:103 msgid "Password is already in use" msgstr "" -#: apps/account/tasks.py:18 -msgid "Password resetting" -msgstr "" - -#: apps/account/tasks.py:31 apps/account/tasks.py:43 -msgid "Validate new email address" -msgstr "" - -#: apps/advertisement/apps.py:7 +#: apps/advertisement/apps.py:7 apps/main/models.py:359 msgid "advertisement" msgstr "" -#: apps/advertisement/models.py:15 +#: apps/advertisement/models.py:43 apps/collection/models.py:748 +#: apps/collection/models.py:968 apps/establishment/models.py:527 +#: apps/establishment/models.py:1288 apps/establishment/models.py:1353 +#: apps/location/models.py:286 apps/location/models.py:317 +#: apps/location/models.py:344 apps/main/models.py:258 apps/main/models.py:443 +#: apps/news/models.py:283 apps/notification/models.py:118 +#: apps/partner/models.py:18 apps/product/models.py:289 +#: apps/product/models.py:526 apps/product/models.py:592 +#: apps/recipe/models.py:61 apps/review/models.py:90 apps/review/models.py:130 +#: apps/review/models.py:158 apps/review/models.py:175 apps/tag/models.py:45 +msgid "old id" +msgstr "" + +#: apps/advertisement/models.py:45 msgid "Ad URL" msgstr "" -#: apps/advertisement/models.py:16 -msgid "Block width" -msgstr "" - -#: apps/advertisement/models.py:17 -msgid "Block height" -msgstr "" - -#: apps/advertisement/models.py:18 +#: apps/advertisement/models.py:46 msgid "Block level" msgstr "" -#: apps/advertisement/models.py:22 apps/advertisement/models.py:23 +#: apps/advertisement/models.py:48 apps/collection/models.py:39 +#: apps/collection/models.py:269 +msgid "start" +msgstr "" + +#: apps/advertisement/models.py:49 apps/collection/models.py:41 +msgid "end" +msgstr "" + +#: apps/advertisement/models.py:52 apps/comment/models.py:81 +#: apps/main/models.py:440 apps/tag/models.py:188 +msgid "site" +msgstr "" + +#: apps/advertisement/models.py:56 apps/main/models.py:392 +msgid "page type" +msgstr "" + +#: apps/advertisement/models.py:57 +msgid "display duration in seconds" +msgstr "" + +#: apps/advertisement/models.py:60 +msgid "Probability to show" +msgstr "" + +#: apps/advertisement/models.py:61 +msgid "How many times shown" +msgstr "" + +#: apps/advertisement/models.py:65 msgid "Advertisement" msgstr "" +#: apps/advertisement/models.py:66 +msgid "Advertisements" +msgstr "" + #: apps/authorization/apps.py:8 msgid "Authorization" msgstr "" @@ -169,20 +327,16 @@ msgstr "" msgid "Refresh tokens" msgstr "" -#: apps/authorization/tasks.py:18 +#: apps/authorization/tasks.py:18 apps/authorization/tasks.py:19 msgid "Email confirmation" msgstr "" -#: apps/authorization/views/common.py:40 -msgid "Application is not found" +#: apps/authorization/views/common.py:69 +msgid "Validation OAuth2 request data error" msgstr "" -#: apps/authorization/views/common.py:50 -msgid "Not found an application with this source" -msgstr "" - -#: apps/booking/apps.py:7 apps/booking/models/models.py:66 -#: apps/booking/models/models.py:67 +#: apps/booking/apps.py:7 apps/booking/models/models.py:69 +#: apps/booking/models/models.py:70 msgid "Booking" msgstr "" @@ -206,89 +360,254 @@ msgstr "" msgid "external service booking id" msgstr "" +#: apps/booking/models/models.py:27 +msgid "stripe service payment key" +msgstr "" + #: apps/booking/models/models.py:28 +msgid "stripe service pre-payed booking token" +msgstr "" + +#: apps/booking/models/models.py:29 +msgid "prepayment price" +msgstr "" + +#: apps/booking/models/models.py:31 msgid "booking owner" msgstr "" -#: apps/collection/apps.py:7 apps/collection/models.py:80 -#: apps/collection/models.py:106 +#: apps/booking/models/services.py:37 +msgid "This field is required" +msgstr "" + +#: apps/collection/apps.py:7 apps/collection/models.py:105 msgid "collection" msgstr "" -#: apps/collection/models.py:17 apps/establishment/models.py:241 -#: apps/establishment/models.py:504 apps/location/models.py:34 -#: apps/location/models.py:55 apps/main/models.py:227 apps/main/models.py:278 -#: apps/news/models.py:14 +#: apps/collection/models.py:29 apps/collection/models.py:78 +#: apps/collection/models.py:690 apps/establishment/models.py:528 +#: apps/establishment/models.py:1214 apps/establishment/models.py:1450 +#: apps/location/models.py:101 apps/location/models.py:280 +#: apps/location/models.py:313 apps/location/models.py:341 +#: apps/main/models.py:32 apps/main/models.py:223 apps/main/models.py:386 +#: apps/main/models.py:428 apps/news/models.py:64 +#: apps/notification/models.py:20 apps/partner/models.py:19 +#: apps/product/models.py:260 apps/product/models.py:490 +#: apps/product/models.py:521 apps/review/models.py:161 msgid "name" msgstr "" -#: apps/collection/models.py:26 -msgid "start" -msgstr "" - -#: apps/collection/models.py:27 -msgid "end" -msgstr "" - -#: apps/collection/models.py:54 +#: apps/collection/models.py:74 msgid "Ordinary" msgstr "" -#: apps/collection/models.py:55 +#: apps/collection/models.py:75 msgid "Pop" msgstr "" -#: apps/collection/models.py:60 +#: apps/collection/models.py:82 msgid "Collection type" msgstr "" -#: apps/collection/models.py:62 apps/establishment/models.py:280 +#: apps/collection/models.py:84 apps/comment/models.py:76 +#: apps/establishment/models.py:574 msgid "Publish status" msgstr "" -#: apps/collection/models.py:64 +#: apps/collection/models.py:86 msgid "Position on top" msgstr "" -#: apps/collection/models.py:66 apps/location/models.py:40 -#: apps/location/models.py:60 apps/main/models.py:226 apps/news/models.py:135 +#: apps/collection/models.py:88 apps/location/models.py:107 +#: apps/location/models.py:155 apps/location/models.py:283 +#: apps/main/models.py:222 apps/main/models.py:269 apps/news/models.py:319 +#: apps/notification/models.py:24 msgid "country" msgstr "" -#: apps/collection/models.py:68 +#: apps/collection/models.py:90 msgid "collection block properties" msgstr "" -#: apps/collection/models.py:71 apps/establishment/models.py:245 -#: apps/establishment/models.py:507 apps/news/models.py:111 +#: apps/collection/models.py:93 apps/establishment/models.py:535 +#: apps/establishment/models.py:1217 apps/location/models.py:289 +#: apps/main/models.py:434 apps/news/models.py:295 apps/product/models.py:261 +#: apps/review/models.py:163 msgid "description" msgstr "" -#: apps/collection/models.py:74 +#: apps/collection/models.py:96 msgid "Collection slug" msgstr "" -#: apps/collection/models.py:81 +#: apps/collection/models.py:106 msgid "collections" msgstr "" -#: apps/collection/models.py:99 -msgid "parent" +#: apps/collection/models.py:260 +msgid "Restaurant" msgstr "" -#: apps/collection/models.py:103 -msgid "advertorials" +#: apps/collection/models.py:261 +msgid "Artisan" msgstr "" -#: apps/collection/models.py:112 +#: apps/collection/models.py:262 +msgid "Wine" +msgstr "" + +#: apps/collection/models.py:267 +msgid "guide type" +msgstr "" + +#: apps/collection/models.py:273 +msgid "guide vintage year" +msgstr "" + +#: apps/collection/models.py:275 +msgid "slug" +msgstr "" + +#: apps/collection/models.py:278 apps/news/models.py:336 +msgid "site settings" +msgstr "" + +#: apps/collection/models.py:283 +msgid "* after rebuild guide, refresh count of related guide elements" +msgstr "" + +#: apps/collection/models.py:284 +msgid "count of related guide elements during initialization" +msgstr "" + +#: apps/collection/models.py:291 apps/collection/models.py:463 msgid "guide" msgstr "" -#: apps/collection/models.py:113 +#: apps/collection/models.py:292 msgid "guides" msgstr "" -#: apps/comment/apps.py:7 +#: apps/collection/models.py:413 +msgid "number of pages" +msgstr "" + +#: apps/collection/models.py:414 +msgid "the total number of reserved pages" +msgstr "" + +#: apps/collection/models.py:416 +msgid "number of right pages" +msgstr "" + +#: apps/collection/models.py:417 +msgid "the number of right pages (which are part of total number)." +msgstr "" + +#: apps/collection/models.py:420 apps/collection/models.py:974 +msgid "guide element" +msgstr "" + +#: apps/collection/models.py:427 +msgid "advertorial" +msgstr "" + +#: apps/collection/models.py:428 +msgid "advertorials" +msgstr "" + +#: apps/collection/models.py:449 +msgid "with mark" +msgstr "" + +#: apps/collection/models.py:450 +msgid "exclude empty marks?" +msgstr "" + +#: apps/collection/models.py:453 +msgid "max mark" +msgstr "" + +#: apps/collection/models.py:455 +msgid "mark under" +msgstr "" + +#: apps/collection/models.py:456 +msgid "min mark" +msgstr "" + +#: apps/collection/models.py:458 +msgid "mark over" +msgstr "" + +#: apps/collection/models.py:470 +msgid "guide filter" +msgstr "" + +#: apps/collection/models.py:471 +msgid "guide filters" +msgstr "" + +#: apps/collection/models.py:694 apps/collection/models.py:943 +msgid "guide element type" +msgstr "" + +#: apps/collection/models.py:695 +msgid "guide element types" +msgstr "" + +#: apps/collection/models.py:709 apps/collection/models.py:744 +msgid "section name" +msgstr "" + +#: apps/collection/models.py:715 +msgid "guide wine color section" +msgstr "" + +#: apps/collection/models.py:716 +msgid "guide wine color sections" +msgstr "" + +#: apps/collection/models.py:727 +msgid "category name" +msgstr "" + +#: apps/collection/models.py:733 +msgid "guide element section category" +msgstr "" + +#: apps/collection/models.py:734 +msgid "guide element section categories" +msgstr "" + +#: apps/collection/models.py:746 apps/establishment/admin.py:121 +#: apps/establishment/models.py:1276 +msgid "category" +msgstr "" + +#: apps/collection/models.py:754 +msgid "guide element section" +msgstr "" + +#: apps/collection/models.py:755 +msgid "guide element sections" +msgstr "" + +#: apps/collection/models.py:966 +msgid "label photo" +msgstr "" + +#: apps/collection/models.py:975 +msgid "guide elements" +msgstr "" + +#: apps/collection/views/back.py:177 apps/collection/views/back.py:193 +#: apps/collection/views/back.py:209 apps/main/views/back.py:174 +#: apps/main/views/back.py:190 +msgid "The file will be sent to your email." +msgstr "" + +#: apps/comment/apps.py:7 apps/review/models.py:132 msgid "comment" msgstr "" @@ -296,23 +615,41 @@ msgstr "" msgid "comments" msgstr "" -#: apps/comment/models.py:32 +#: apps/comment/models.py:64 apps/product/models.py:253 +#: apps/recipe/models.py:42 +msgid "Waiting" +msgstr "" + +#: apps/comment/models.py:65 apps/main/models.py:158 apps/product/models.py:251 +#: apps/recipe/models.py:44 +msgid "Published" +msgstr "Опубликовано" + +#: apps/comment/models.py:66 +msgid "Rejected" +msgstr "" + +#: apps/comment/models.py:67 +msgid "Deleted" +msgstr "" + +#: apps/comment/models.py:70 msgid "Comment text" msgstr "" -#: apps/comment/models.py:34 +#: apps/comment/models.py:73 msgid "Mark" msgstr "" -#: apps/comment/models.py:44 -msgid "Locale" +#: apps/comment/models.py:79 +msgid "status" msgstr "" -#: apps/comment/models.py:48 +#: apps/comment/models.py:90 msgid "Comment" msgstr "" -#: apps/comment/models.py:49 +#: apps/comment/models.py:91 msgid "Comments" msgstr "" @@ -324,253 +661,503 @@ msgstr "" msgid "default language" msgstr "" -#: apps/establishment/admin.py:87 apps/establishment/models.py:529 -#: apps/main/models.py:248 -msgid "category" +#: apps/establishment/filters.py:126 apps/news/filters.py:55 +msgid "Type at least 3 characters to search please." msgstr "" -#: apps/establishment/apps.py:8 apps/establishment/models.py:310 -#: apps/establishment/models.py:418 -msgid "Establishment" -msgstr "" - -#: apps/establishment/models.py:30 apps/establishment/models.py:54 -#: apps/establishment/models.py:391 apps/recipe/models.py:52 +#: apps/establishment/models.py:50 apps/establishment/models.py:91 +#: apps/establishment/models.py:935 apps/recipe/models.py:53 msgid "Description" msgstr "" -#: apps/establishment/models.py:32 +#: apps/establishment/models.py:53 apps/establishment/models.py:94 +#: apps/establishment/models.py:533 apps/establishment/models.py:941 +#: apps/notification/models.py:18 apps/product/models.py:51 +#: apps/product/models.py:89 +msgid "Index name" +msgstr "" + +#: apps/establishment/models.py:54 apps/product/models.py:52 msgid "Use subtypes" msgstr "" -#: apps/establishment/models.py:37 +#: apps/establishment/models.py:58 apps/establishment/models.py:101 +#: apps/product/models.py:56 apps/tag/models.py:176 +msgid "Tag categories" +msgstr "" + +#: apps/establishment/models.py:67 msgid "Establishment type" msgstr "" -#: apps/establishment/models.py:38 +#: apps/establishment/models.py:68 msgid "Establishment types" msgstr "" -#: apps/establishment/models.py:58 +#: apps/establishment/models.py:97 apps/product/models.py:266 msgid "Type" msgstr "" -#: apps/establishment/models.py:65 -msgid "Establishment subtype" -msgstr "" - -#: apps/establishment/models.py:66 +#: apps/establishment/models.py:113 msgid "Establishment subtypes" msgstr "" -#: apps/establishment/models.py:70 +#: apps/establishment/models.py:117 msgid "Establishment type is not use subtypes." msgstr "" -#: apps/establishment/models.py:242 +#: apps/establishment/models.py:530 msgid "Transliterated name" msgstr "" -#: apps/establishment/models.py:249 +#: apps/establishment/models.py:532 +msgid "Western name" +msgstr "" + +#: apps/establishment/models.py:539 apps/product/models.py:275 msgid "public mark" msgstr "" -#: apps/establishment/models.py:252 +#: apps/establishment/models.py:543 msgid "toque number" msgstr "" -#: apps/establishment/models.py:256 +#: apps/establishment/models.py:547 msgid "type" msgstr "" -#: apps/establishment/models.py:259 +#: apps/establishment/models.py:551 msgid "subtype" msgstr "" -#: apps/establishment/models.py:262 apps/news/models.py:131 +#: apps/establishment/models.py:554 apps/establishment/models.py:1473 +#: apps/news/models.py:34 apps/news/models.py:315 msgid "address" msgstr "" -#: apps/establishment/models.py:265 +#: apps/establishment/models.py:557 msgid "price level" msgstr "" -#: apps/establishment/models.py:267 +#: apps/establishment/models.py:559 msgid "Web site URL" msgstr "" -#: apps/establishment/models.py:269 +#: apps/establishment/models.py:561 msgid "Facebook URL" msgstr "" -#: apps/establishment/models.py:271 +#: apps/establishment/models.py:563 msgid "Twitter URL" msgstr "" -#: apps/establishment/models.py:273 +#: apps/establishment/models.py:565 +msgid "Instagram URL" +msgstr "" + +#: apps/establishment/models.py:567 msgid "Lafourchette URL" msgstr "" -#: apps/establishment/models.py:274 +#: apps/establishment/models.py:568 msgid "guestonline id" msgstr "" -#: apps/establishment/models.py:276 +#: apps/establishment/models.py:570 msgid "lastable id" msgstr "" -#: apps/establishment/models.py:279 +#: apps/establishment/models.py:573 msgid "Booking URL" msgstr "" -#: apps/establishment/models.py:282 +#: apps/establishment/models.py:576 apps/establishment/models.py:1285 msgid "Establishment schedule" msgstr "" -#: apps/establishment/models.py:289 +#: apps/establishment/models.py:579 msgid "Transportation" msgstr "" -#: apps/establishment/models.py:293 +#: apps/establishment/models.py:583 msgid "Collections" msgstr "" -#: apps/establishment/models.py:294 apps/news/models.py:128 +#: apps/establishment/models.py:585 msgid "Preview image URL path" msgstr "" -#: apps/establishment/models.py:297 +#: apps/establishment/models.py:588 msgid "Establishment slug" msgstr "" -#: apps/establishment/models.py:311 -msgid "Establishments" +#: apps/establishment/models.py:593 apps/product/models.py:296 +#: apps/product/models.py:591 apps/tag/models.py:65 +msgid "Tag" msgstr "" -#: apps/establishment/models.py:399 apps/establishment/models.py:425 -msgid "Position" -msgstr "" - -#: apps/establishment/models.py:400 -msgid "Positions" -msgstr "" - -#: apps/establishment/models.py:420 apps/establishment/models.py:445 -msgid "Employee" -msgstr "" - -#: apps/establishment/models.py:421 -msgid "From date" -msgstr "" - -#: apps/establishment/models.py:423 -msgid "To date" -msgstr "" - -#: apps/establishment/models.py:436 -msgid "Last name" -msgstr "" - -#: apps/establishment/models.py:446 -msgid "Employees" -msgstr "" - -#: apps/establishment/models.py:460 -msgid "contact phone" -msgstr "" - -#: apps/establishment/models.py:461 -msgid "contact phones" -msgstr "" - -#: apps/establishment/models.py:474 -msgid "contact email" -msgstr "" - -#: apps/establishment/models.py:475 -msgid "contact emails" -msgstr "" - -#: apps/establishment/models.py:510 -msgid "price" -msgstr "" - -#: apps/establishment/models.py:511 -msgid "is signature plate" -msgstr "" - -#: apps/establishment/models.py:513 apps/main/models.py:281 +#: apps/establishment/models.py:600 apps/establishment/models.py:1223 +#: apps/main/models.py:39 msgid "currency" msgstr "" -#: apps/establishment/models.py:516 apps/establishment/models.py:536 -#: apps/establishment/models.py:537 -msgid "menu" +#: apps/establishment/models.py:604 apps/product/models.py:483 +msgid "purchased plaques" msgstr "" -#: apps/establishment/models.py:519 -msgid "plate" +#: apps/establishment/models.py:605 +msgid "" +"Attribute from legacy db.\n" +"Must be deleted after the implementation of the market." msgstr "" -#: apps/establishment/models.py:520 -msgid "plates" +#: apps/establishment/models.py:615 +msgid "Establishments" msgstr "" -#: apps/establishment/models.py:532 apps/establishment/models.py:542 +#: apps/establishment/models.py:896 apps/product/models.py:609 +#: apps/review/models.py:69 +msgid "text" +msgstr "" + +#: apps/establishment/models.py:899 apps/establishment/models.py:917 +#: apps/establishment/models.py:1279 apps/establishment/models.py:1356 +#: apps/establishment/models.py:1449 apps/product/models.py:273 +#: apps/product/models.py:472 msgid "establishment" msgstr "" -#: apps/establishment/models.py:544 apps/main/models.py:207 -#: apps/news/models.py:105 +#: apps/establishment/models.py:903 apps/product/models.py:616 +#: apps/review/models.py:103 apps/review/models.py:138 +msgid "author" +msgstr "" + +#: apps/establishment/models.py:909 +msgid "establishment notes" +msgstr "" + +#: apps/establishment/models.py:910 +msgid "establishment note" +msgstr "" + +#: apps/establishment/models.py:921 apps/establishment/models.py:1311 +#: apps/product/models.py:545 apps/review/models.py:188 +msgid "image" +msgstr "" + +#: apps/establishment/models.py:925 +msgid "establishment gallery" +msgstr "" + +#: apps/establishment/models.py:926 +msgid "establishment galleries" +msgstr "" + +#: apps/establishment/models.py:946 apps/establishment/models.py:983 +msgid "Position" +msgstr "" + +#: apps/establishment/models.py:947 +msgid "Positions" +msgstr "" + +#: apps/establishment/models.py:977 apps/establishment/models.py:1140 +msgid "Employee" +msgstr "" + +#: apps/establishment/models.py:978 +msgid "From date" +msgstr "" + +#: apps/establishment/models.py:981 +msgid "To date" +msgstr "" + +#: apps/establishment/models.py:988 apps/establishment/models.py:1128 +msgid "Old id" +msgstr "" + +#: apps/establishment/models.py:1102 +msgid "Last Name" +msgstr "" + +#: apps/establishment/models.py:1110 +msgid "Male" +msgstr "" + +#: apps/establishment/models.py:1111 +msgid "Female" +msgstr "" + +#: apps/establishment/models.py:1113 +msgid "Sex" +msgstr "" + +#: apps/establishment/models.py:1115 +msgid "Birth date" +msgstr "" + +#: apps/establishment/models.py:1117 apps/notification/models.py:106 +msgid "Email" +msgstr "" + +#: apps/establishment/models.py:1119 +msgid "Toque number" +msgstr "" + +#: apps/establishment/models.py:1126 apps/news/models.py:321 +#: apps/tag/models.py:66 +msgid "Tags" +msgstr "" + +#: apps/establishment/models.py:1129 +msgid "Available for events" +msgstr "" + +#: apps/establishment/models.py:1133 apps/location/models.py:170 +msgid "image instance of model Image" +msgstr "" + +#: apps/establishment/models.py:1141 +msgid "Employees" +msgstr "" + +#: apps/establishment/models.py:1188 +msgid "contact phone" +msgstr "" + +#: apps/establishment/models.py:1189 apps/establishment/models.py:1453 +msgid "contact phones" +msgstr "" + +#: apps/establishment/models.py:1202 +msgid "contact email" +msgstr "" + +#: apps/establishment/models.py:1203 +msgid "contact emails" +msgstr "" + +#: apps/establishment/models.py:1220 apps/review/models.py:141 +msgid "price" +msgstr "" + +#: apps/establishment/models.py:1221 +msgid "is signature plate" +msgstr "" + +#: apps/establishment/models.py:1226 +msgid "currency code" +msgstr "" + +#: apps/establishment/models.py:1230 apps/establishment/models.py:1293 +#: apps/establishment/models.py:1294 apps/establishment/models.py:1304 +#: apps/establishment/models.py:1326 +msgid "menu" +msgstr "" + +#: apps/establishment/models.py:1240 +msgid "plate" +msgstr "" + +#: apps/establishment/models.py:1241 +msgid "plates" +msgstr "" + +#: apps/establishment/models.py:1281 +msgid "is drinks included" +msgstr "" + +#: apps/establishment/models.py:1316 +msgid "menu gallery" +msgstr "" + +#: apps/establishment/models.py:1317 +msgid "menu galleries" +msgstr "" + +#: apps/establishment/models.py:1330 apps/establishment/models.py:1342 +#: apps/gallery/models.py:29 apps/main/models.py:196 apps/main/models.py:402 +#: apps/news/models.py:47 apps/news/models.py:287 msgid "title" msgstr "" -#: apps/establishment/models.py:545 -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2234 -msgid "URL" +#: apps/establishment/models.py:1332 +msgid "File" msgstr "" -#: apps/establishment/models.py:548 +#: apps/establishment/models.py:1337 +msgid "menu upload" +msgstr "" + +#: apps/establishment/models.py:1338 +msgid "menu uploads" +msgstr "" + +#: apps/establishment/models.py:1345 +msgid "social choice" +msgstr "" + +#: apps/establishment/models.py:1346 +msgid "social choices" +msgstr "" + +#: apps/establishment/models.py:1362 apps/establishment/models.py:1369 msgid "social network" msgstr "" -#: apps/establishment/models.py:549 +#: apps/establishment/models.py:1366 +msgid "URL" +msgstr "" + +#: apps/establishment/models.py:1370 msgid "social networks" msgstr "" -#: apps/establishment/serializers/common.py:237 -#: apps/timetable/serialziers.py:47 +#: apps/establishment/models.py:1411 +msgid "One" +msgstr "" + +#: apps/establishment/models.py:1412 +msgid "Two" +msgstr "" + +#: apps/establishment/models.py:1413 +msgid "Three" +msgstr "" + +#: apps/establishment/models.py:1414 +msgid "Four" +msgstr "" + +#: apps/establishment/models.py:1415 +msgid "Five" +msgstr "" + +#: apps/establishment/models.py:1430 apps/establishment/models.py:1431 +msgid "Rating strategy" +msgstr "" + +#: apps/establishment/models.py:1456 +msgid "fax numbers" +msgstr "" + +#: apps/establishment/models.py:1459 +msgid "legal entity" +msgstr "" + +#: apps/establishment/models.py:1462 +msgid "registry number" +msgstr "" + +#: apps/establishment/models.py:1465 +msgid "VAT identification number" +msgstr "" + +#: apps/establishment/models.py:1469 +msgid "sic code" +msgstr "" + +#: apps/establishment/models.py:1479 +msgid "company" +msgstr "" + +#: apps/establishment/models.py:1480 +msgid "companies" +msgstr "" + +#: apps/establishment/serializers/back.py:467 +msgid "Establishment not found" +msgstr "" + +#: apps/establishment/serializers/back.py:470 +#: apps/establishment/serializers/back.py:680 apps/news/serializers.py:445 +#: apps/product/serializers/back.py:42 +msgid "Image not found" +msgstr "" + +#: apps/establishment/serializers/back.py:476 +#: apps/product/serializers/back.py:48 +msgid "Image is already added." +msgstr "" + +#: apps/establishment/serializers/back.py:678 +msgid "Menu not found" +msgstr "" + +#: apps/establishment/serializers/common.py:212 +#, python-brace-format +msgid "{entity_class.__name__} not found." +msgstr "" + +#: apps/establishment/serializers/common.py:547 +#: apps/timetable/serialziers.py:61 msgid "Establishment not found." msgstr "" -#: apps/establishment/serializers/common.py:288 +#: apps/establishment/serializers/common.py:586 +#: apps/establishment/serializers/common.py:614 apps/news/serializers.py:469 +#: apps/news/serializers.py:495 apps/product/serializers/common.py:183 msgid "Object not found." msgstr "" +#: apps/establishment/serializers/common.py:675 +msgid "Fax is already reserved." +msgstr "" + +#: apps/establishment/serializers/common.py:679 +msgid "Phones is already reserved." +msgstr "" + #: apps/favorites/apps.py:7 apps/favorites/models.py:32 #: apps/favorites/models.py:33 msgid "Favorites" msgstr "" -#: apps/gallery/apps.py:7 +#: apps/gallery/apps.py:7 apps/news/models.py:495 msgid "gallery" msgstr "" -#: apps/gallery/models.py:12 -msgid "Image file" +#: apps/gallery/models.py:20 +msgid "Horizontal" msgstr "" -#: apps/gallery/models.py:16 apps/utils/models.py:147 apps/utils/models.py:176 -#: apps/utils/models.py:207 -#: venv/lib/python3.6/site-packages/django/db/models/fields/files.py:360 +#: apps/gallery/models.py:21 +msgid "Vertical" +msgstr "" + +#: apps/gallery/models.py:25 +msgid "image file" +msgstr "" + +#: apps/gallery/models.py:28 +msgid "image orientation" +msgstr "" + +#: apps/gallery/models.py:35 apps/utils/models.py:169 apps/utils/models.py:198 +#: apps/utils/models.py:207 apps/utils/models.py:248 apps/utils/models.py:283 msgid "Image" msgstr "" -#: apps/gallery/models.py:17 +#: apps/gallery/models.py:36 msgid "Images" msgstr "" -#: apps/location/admin.py:28 apps/main/apps.py:8 apps/main/models.py:191 +#: apps/gallery/serializers.py:43 +#, python-format +msgid "File size too large: %s bytes" +msgstr "" + +#: apps/gallery/serializers.py:92 +#, python-format +msgid "Unrecognized crop option: %s" +msgstr "" + +#: apps/gallery/serializers.py:139 +msgid "Image not found." +msgstr "" + +#: apps/location/admin.py:28 apps/main/apps.py:8 apps/main/models.py:161 msgid "Main" msgstr "" @@ -586,296 +1173,781 @@ msgstr "" msgid "location" msgstr "" -#: apps/location/models.py:19 +#: apps/location/models.py:42 msgid "Code" msgstr "" -#: apps/location/models.py:20 +#: apps/location/models.py:43 msgid "Low price" msgstr "" -#: apps/location/models.py:21 +#: apps/location/models.py:44 msgid "High price" msgstr "" -#: apps/location/models.py:22 apps/translation/models.py:34 +#: apps/location/models.py:45 apps/translation/models.py:43 msgid "Languages" msgstr "" -#: apps/location/models.py:27 +#: apps/location/models.py:46 apps/translation/models.py:35 +msgid "is active" +msgstr "" + +#: apps/location/models.py:56 msgid "Countries" msgstr "" -#: apps/location/models.py:35 apps/location/models.py:56 +#: apps/location/models.py:102 apps/location/models.py:150 msgid "code" msgstr "" -#: apps/location/models.py:37 apps/location/models.py:58 +#: apps/location/models.py:104 apps/location/models.py:153 msgid "parent region" msgstr "" -#: apps/location/models.py:45 +#: apps/location/models.py:116 msgid "regions" msgstr "" -#: apps/location/models.py:46 +#: apps/location/models.py:117 msgid "region" msgstr "" -#: apps/location/models.py:63 apps/location/models.py:85 +#: apps/location/models.py:149 +msgid "City name json" +msgstr "" + +#: apps/location/models.py:158 apps/location/models.py:222 msgid "postal code" msgstr "" -#: apps/location/models.py:63 apps/location/models.py:86 +#: apps/location/models.py:158 apps/location/models.py:223 msgid "Ex.: 350018" msgstr "" -#: apps/location/models.py:65 +#: apps/location/models.py:160 msgid "is island" msgstr "" -#: apps/location/models.py:68 +#: apps/location/models.py:177 msgid "cities" msgstr "" -#: apps/location/models.py:69 apps/location/models.py:78 +#: apps/location/models.py:178 apps/location/models.py:215 msgid "city" msgstr "" -#: apps/location/models.py:80 +#: apps/location/models.py:217 msgid "street name 1" msgstr "" -#: apps/location/models.py:82 +#: apps/location/models.py:219 msgid "street name 2" msgstr "" -#: apps/location/models.py:83 +#: apps/location/models.py:220 msgid "number" msgstr "" -#: apps/location/models.py:88 +#: apps/location/models.py:225 apps/location/models.py:285 +#: apps/product/models.py:525 msgid "Coordinates" msgstr "" -#: apps/location/models.py:93 apps/location/models.py:94 +#: apps/location/models.py:227 +msgid "District name" +msgstr "" + +#: apps/location/models.py:233 apps/location/models.py:234 msgid "Address" msgstr "" -#: apps/location/serializers/common.py:120 -#: apps/location/serializers/common.py:125 +#: apps/location/models.py:299 +msgid "wine regions" +msgstr "" + +#: apps/location/models.py:300 apps/location/models.py:343 +#: apps/location/models.py:362 +msgid "wine region" +msgstr "" + +#: apps/location/models.py:316 apps/location/models.py:325 +#: apps/location/models.py:365 +msgid "wine sub region" +msgstr "" + +#: apps/location/models.py:324 +msgid "wine sub regions" +msgstr "" + +#: apps/location/models.py:351 apps/product/models.py:285 +msgid "wine village" +msgstr "" + +#: apps/location/models.py:352 +msgid "wine villages" +msgstr "" + +#: apps/location/models.py:380 apps/location/models.py:398 +#: apps/product/models.py:541 apps/product/models.py:612 +msgid "product" +msgstr "" + +#: apps/location/models.py:386 +msgid "establishment wine origin address" +msgstr "" + +#: apps/location/models.py:387 +msgid "establishment wine origin addresses" +msgstr "" + +#: apps/location/models.py:404 +msgid "wine origin address" +msgstr "" + +#: apps/location/models.py:405 +msgid "wine origin addresses" +msgstr "" + +#: apps/location/serializers/common.py:184 +#: apps/location/serializers/common.py:189 msgid "Invalid value" msgstr "" -#: apps/main/models.py:114 -msgid "Subdomain" +#: apps/main/models.py:34 +msgid "sign" msgstr "" -#: apps/main/models.py:119 -msgid "Default site" -msgstr "" - -#: apps/main/models.py:121 -msgid "Pinterest page URL" -msgstr "" - -#: apps/main/models.py:123 -msgid "Twitter page URL" -msgstr "" - -#: apps/main/models.py:125 -msgid "Facebook page URL" -msgstr "" - -#: apps/main/models.py:127 -msgid "Instagram page URL" -msgstr "" - -#: apps/main/models.py:129 -msgid "Contact email" -msgstr "" - -#: apps/main/models.py:131 -msgid "Config" -msgstr "" - -#: apps/main/models.py:133 -msgid "AD config" -msgstr "" - -#: apps/main/models.py:140 -msgid "Site setting" -msgstr "" - -#: apps/main/models.py:141 -msgid "Site settings" -msgstr "" - -#: apps/main/models.py:171 -msgid "Feature" -msgstr "" - -#: apps/main/models.py:172 -msgid "Features" -msgstr "" - -#: apps/main/models.py:190 apps/news/models.py:98 apps/recipe/models.py:42 -msgid "Published" -msgstr "" - -#: apps/main/models.py:198 -msgid "Site feature" -msgstr "" - -#: apps/main/models.py:199 -msgid "Site features" -msgstr "" - -#: apps/main/models.py:209 -msgid "vintage year" -msgstr "" - -#: apps/main/models.py:245 -msgid "label" -msgstr "" - -#: apps/main/models.py:251 apps/main/models.py:252 -msgid "metadata" -msgstr "" - -#: apps/main/models.py:282 +#: apps/main/models.py:40 msgid "currencies" msgstr "" -#: apps/main/models.py:302 apps/main/models.py:303 -msgid "Carousel" +#: apps/main/models.py:58 +msgid "Subdomain" msgstr "" -#: apps/main/models.py:365 apps/translation/models.py:49 -msgid "Page" +#: apps/main/models.py:63 +msgid "Default site" msgstr "" -#: apps/main/models.py:366 -msgid "Pages" +#: apps/main/models.py:65 +msgid "Pinterest page URL" msgstr "" -#: apps/news/apps.py:7 apps/news/models.py:145 apps/news/models.py:146 -msgid "news" +#: apps/main/models.py:67 +msgid "Twitter page URL" msgstr "" -#: apps/news/models.py:19 -msgid "news types" +#: apps/main/models.py:69 +msgid "Facebook page URL" msgstr "" -#: apps/news/models.py:20 apps/news/models.py:103 -msgid "news type" +#: apps/main/models.py:71 +msgid "Instagram page URL" msgstr "" -#: apps/news/models.py:96 apps/recipe/models.py:40 -msgid "Waiting" +#: apps/main/models.py:73 +msgid "Contact email" msgstr "" -#: apps/news/models.py:97 apps/recipe/models.py:41 -msgid "Hidden" +#: apps/main/models.py:75 +msgid "Config" msgstr "" -#: apps/news/models.py:99 apps/recipe/models.py:43 -msgid "Published exclusive" +#: apps/main/models.py:77 +msgid "AD config" msgstr "" -#: apps/news/models.py:108 -msgid "subtitle" +#: apps/main/models.py:87 +msgid "Site setting" msgstr "" -#: apps/news/models.py:113 -msgid "Start" +#: apps/main/models.py:128 +msgid "Feature" msgstr "" -#: apps/news/models.py:115 -msgid "End" +#: apps/main/models.py:129 +msgid "Features" msgstr "" -#: apps/news/models.py:117 -msgid "News slug" +#: apps/main/models.py:164 +msgid "backoffice" msgstr "" -#: apps/news/models.py:118 -msgid "playlist" +#: apps/main/models.py:173 +msgid "Site feature" msgstr "" -#: apps/news/models.py:120 apps/notification/models.py:89 -#: apps/recipe/models.py:55 +#: apps/main/models.py:174 +msgid "Site features" +msgstr "" + +#: apps/main/models.py:198 apps/product/models.py:300 +msgid "vintage year" +msgstr "" + +#: apps/main/models.py:205 apps/news/models.py:310 apps/recipe/models.py:55 msgid "State" msgstr "" -#: apps/news/models.py:122 +#: apps/main/models.py:257 +msgid "is international" +msgstr "" + +#: apps/main/models.py:259 +msgid "old title" +msgstr "" + +#: apps/main/models.py:260 +msgid "old link" +msgstr "" + +#: apps/main/models.py:261 +msgid "old attachment_suffix_url" +msgstr "" + +#: apps/main/models.py:262 +msgid "old description" +msgstr "" + +#: apps/main/models.py:263 +msgid "old link_title" +msgstr "" + +#: apps/main/models.py:271 +msgid "old active" +msgstr "" + +#: apps/main/models.py:272 +msgid "is parse" +msgstr "" + +#: apps/main/models.py:278 apps/main/models.py:279 +msgid "Carousel" +msgstr "" + +#: apps/main/models.py:361 +msgid "Block width" +msgstr "" + +#: apps/main/models.py:363 +msgid "Block height" +msgstr "" + +#: apps/main/models.py:369 +msgid "page" +msgstr "" + +#: apps/main/models.py:370 +msgid "pages" +msgstr "" + +#: apps/main/models.py:393 +msgid "page types" +msgstr "" + +#: apps/main/models.py:401 +msgid "link" +msgstr "" + +#: apps/main/models.py:407 +msgid "footer" +msgstr "" + +#: apps/main/models.py:410 +msgid "about_us" +msgstr "" + +#: apps/main/models.py:411 +msgid "copyright" +msgstr "" + +#: apps/main/models.py:412 +msgid "links" +msgstr "" + +#: apps/main/models.py:425 +msgid "table" +msgstr "" + +#: apps/main/models.py:426 +msgid "mailing" +msgstr "" + +#: apps/main/models.py:430 +msgid "display" +msgstr "" + +#: apps/main/models.py:435 +msgid "query" +msgstr "" + +#: apps/main/models.py:437 +msgid "user" +msgstr "" + +#: apps/main/models.py:448 +msgid "panel" +msgstr "" + +#: apps/main/models.py:449 +msgid "panels" +msgstr "" + +#: apps/main/models.py:557 +msgid "read" +msgstr "" + +#: apps/main/models.py:558 +msgid "write" +msgstr "" + +#: apps/main/models.py:562 +msgid "sections" +msgstr "" + +#: apps/main/models.py:568 +msgid "permission mode" +msgstr "" + +#: apps/main/models.py:572 +msgid "Navigation bar item permission" +msgstr "" + +#: apps/main/models.py:573 +msgid "Navigation bar item permissions" +msgstr "" + +#: apps/news/apps.py:7 apps/news/models.py:346 apps/news/models.py:347 +#: apps/news/models.py:491 +msgid "news" +msgstr "" + +#: apps/news/filters.py:17 apps/recipe/models.py:70 +msgid "Recipes" +msgstr "" + +#: apps/news/models.py:30 +msgid "Start datetime" +msgstr "" + +#: apps/news/models.py:32 +msgid "End datetime" +msgstr "" + +#: apps/news/models.py:37 +msgid "event name" +msgstr "" + +#: apps/news/models.py:40 +msgid "content" +msgstr "" + +#: apps/news/models.py:51 +msgid "Content URL path" +msgstr "" + +#: apps/news/models.py:78 +msgid "news types" +msgstr "" + +#: apps/news/models.py:79 apps/news/models.py:285 +msgid "news type" +msgstr "" + +#: apps/news/models.py:274 +msgid "remove" +msgstr "удалено" + +#: apps/news/models.py:275 +msgid "hidden" +msgstr "скрыто" + +#: apps/news/models.py:276 +msgid "published" +msgstr "опубликовано" + +#: apps/news/models.py:277 +msgid "not published" +msgstr "не опубликовано" + +#: apps/news/models.py:290 +msgid "Title for searching via BO" +msgstr "" + +#: apps/news/models.py:292 +msgid "subtitle" +msgstr "" + +#: apps/news/models.py:298 +msgid "Is description for certain locale active" +msgstr "" + +#: apps/news/models.py:300 +msgid "News publication date" +msgstr "" + +#: apps/news/models.py:301 +msgid "date since when news item is published" +msgstr "" + +#: apps/news/models.py:302 +msgid "News publication time" +msgstr "" + +#: apps/news/models.py:303 +msgid "time since when news item is published" +msgstr "" + +#: apps/news/models.py:305 +msgid "End" +msgstr "" + +#: apps/news/models.py:307 +msgid "Slugs for current news obj" +msgstr "" + +#: apps/news/models.py:312 msgid "Is highlighted" msgstr "" +#: apps/news/models.py:330 +msgid "agenda" +msgstr "" + +#: apps/news/models.py:334 +msgid "banner" +msgstr "" + +#: apps/news/models.py:338 +msgid "Duplication datetime" +msgstr "" + +#: apps/news/models.py:340 +msgid "Field to detect doubles" +msgstr "" + +#: apps/news/models.py:499 +msgid "news gallery" +msgstr "" + +#: apps/news/models.py:500 +msgid "news galleries" +msgstr "" + +#: apps/news/serializers.py:276 apps/news/serializers.py:308 +msgid "Slug should be unique" +msgstr "" + +#: apps/news/serializers.py:443 +msgid "News not found" +msgstr "" + #: apps/notification/apps.py:7 msgid "notification" msgstr "" -#: apps/notification/models.py:73 -msgid "Unusable" -msgstr "" - -#: apps/notification/models.py:74 -msgid "Usable" -msgstr "" - -#: apps/notification/models.py:81 -msgid "Email" -msgstr "" - -#: apps/notification/models.py:83 -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1891 +#: apps/notification/models.py:107 msgid "IP address" msgstr "" -#: apps/notification/models.py:85 +#: apps/notification/models.py:108 msgid "Country code" msgstr "" -#: apps/notification/models.py:87 apps/translation/models.py:26 +#: apps/notification/models.py:109 apps/translation/models.py:31 msgid "Locale identifier" msgstr "" -#: apps/notification/models.py:91 +#: apps/notification/models.py:116 msgid "Token" msgstr "" -#: apps/notification/models.py:98 +#: apps/notification/models.py:127 msgid "Subscriber" msgstr "" -#: apps/notification/models.py:99 +#: apps/notification/models.py:128 msgid "Subscribers" msgstr "" -#: apps/notification/serializers/common.py:29 +#: apps/notification/models.py:190 +msgid "Last unsubscribe date" +msgstr "" + +#: apps/notification/models.py:195 +msgid "Old subscriber id" +msgstr "" + +#: apps/notification/models.py:196 +msgid "Old subscription type id" +msgstr "" + +#: apps/notification/models.py:207 +msgid "Subscribe" +msgstr "" + +#: apps/notification/models.py:208 +msgid "Subscribes" +msgstr "" + +#: apps/notification/serializers/common.py:65 msgid "Does not match user email" msgstr "" -#: apps/notification/serializers/common.py:32 -#: venv/lib/python3.6/site-packages/django/forms/fields.py:53 +#: apps/notification/serializers/common.py:68 msgid "This field is required." msgstr "" -#: apps/partner/apps.py:7 apps/partner/models.py:12 +#: apps/notification/tasks.py:31 +msgid "You have subscribed on news G&M" +msgstr "" + +#: apps/notification/tasks.py:32 +msgid "
" +msgstr "" + +#: apps/notification/tasks.py:46 +msgid "G&M Subscriptions" +msgstr "" + +#: apps/notification/tasks.py:73 +msgid "You have successfully unsubscribed from G&M news" +msgstr "" + +#: apps/partner/apps.py:7 apps/partner/models.py:36 msgid "partner" msgstr "" -#: apps/partner/models.py:9 +#: apps/partner/models.py:14 +msgid "Partner" +msgstr "" + +#: apps/partner/models.py:15 +msgid "Sponsor" +msgstr "" + +#: apps/partner/models.py:20 msgid "Partner URL" msgstr "" -#: apps/partner/models.py:13 +#: apps/partner/models.py:21 +msgid "Partner image URL" +msgstr "" + +#: apps/partner/models.py:31 +msgid "starting date" +msgstr "" + +#: apps/partner/models.py:32 +msgid "expiry date" +msgstr "" + +#: apps/partner/models.py:33 +msgid "price per month" +msgstr "" + +#: apps/partner/models.py:37 msgid "partners" msgstr "" -#: apps/products/apps.py:8 -msgid "products" +#: apps/product/apps.py:7 apps/product/models.py:323 +msgid "Product" +msgstr "" + +#: apps/product/models.py:65 apps/product/models.py:85 +msgid "Product type" +msgstr "" + +#: apps/product/models.py:66 +msgid "Product types" +msgstr "" + +#: apps/product/models.py:98 +msgid "Product subtype" +msgstr "" + +#: apps/product/models.py:99 +msgid "Product subtypes" +msgstr "" + +#: apps/product/models.py:103 +msgid "Product type is not use subtypes." +msgstr "" + +#: apps/product/models.py:242 +msgid "Common" +msgstr "" + +#: apps/product/models.py:243 +msgid "Online" +msgstr "" + +#: apps/product/models.py:252 +msgid "Out_of_production" +msgstr "" + +#: apps/product/models.py:263 +msgid "available" +msgstr "" + +#: apps/product/models.py:269 +msgid "Subtypes" +msgstr "" + +#: apps/product/models.py:278 +msgid "classifications" +msgstr "" + +#: apps/product/models.py:281 +msgid "standards" +msgstr "" + +#: apps/product/models.py:282 apps/product/models.py:294 +#: apps/product/models.py:299 +msgid "attribute from legacy db" +msgstr "" + +#: apps/product/models.py:287 apps/recipe/models.py:62 +msgid "Slug" +msgstr "" + +#: apps/product/models.py:306 +msgid "average price" +msgstr "" + +#: apps/product/models.py:314 +msgid "Serial number" +msgstr "" + +#: apps/product/models.py:324 +msgid "Products" +msgstr "" + +#: apps/product/models.py:463 +msgid "Online product" +msgstr "" + +#: apps/product/models.py:464 +msgid "Online products" +msgstr "" + +#: apps/product/models.py:475 +msgid "plaque" +msgstr "" + +#: apps/product/models.py:477 +msgid "is gifted" +msgstr "" + +#: apps/product/models.py:478 +msgid "quantity" +msgstr "" + +#: apps/product/models.py:482 +msgid "purchased plaque" +msgstr "" + +#: apps/product/models.py:492 apps/review/models.py:162 +msgid "value" +msgstr "" + +#: apps/product/models.py:496 +msgid "unit" +msgstr "" + +#: apps/product/models.py:497 +msgid "units" +msgstr "" + +#: apps/product/models.py:516 +msgid "Appellation" +msgstr "" + +#: apps/product/models.py:517 +msgid "Wine quality" +msgstr "" + +#: apps/product/models.py:518 +msgid "Yard classification" +msgstr "" + +#: apps/product/models.py:523 +msgid "standard type" +msgstr "" + +#: apps/product/models.py:532 +msgid "wine standards" +msgstr "" + +#: apps/product/models.py:533 +msgid "wine standard" +msgstr "" + +#: apps/product/models.py:549 +msgid "product gallery" +msgstr "" + +#: apps/product/models.py:550 +msgid "product galleries" +msgstr "" + +#: apps/product/models.py:558 apps/product/models.py:586 +msgid "classification type" +msgstr "" + +#: apps/product/models.py:561 +msgid "product type" +msgstr "" + +#: apps/product/models.py:564 +msgid "product subtype" +msgstr "" + +#: apps/product/models.py:565 +msgid "" +"Legacy attribute - possible_type (product type).Product type in our case is " +"product subtype." +msgstr "" + +#: apps/product/models.py:570 +msgid "wine classification type" +msgstr "" + +#: apps/product/models.py:571 +msgid "wine classification types" +msgstr "" + +#: apps/product/models.py:589 +msgid "standard" +msgstr "" + +#: apps/product/models.py:598 +msgid "product classification" +msgstr "" + +#: apps/product/models.py:599 +msgid "product classifications" +msgstr "" + +#: apps/product/models.py:622 +msgid "product note" +msgstr "" + +#: apps/product/models.py:623 +msgid "product notes" +msgstr "" + +#: apps/product/serializers/back.py:39 +msgid "Product not found" +msgstr "" + +#: apps/product/serializers/back.py:110 +msgid "Tag category is already attached." +msgstr "" + +#: apps/product/serializers/common.py:229 +msgid "Product not found." msgstr "" #: apps/rating/models.py:11 @@ -886,183 +1958,331 @@ msgstr "" msgid "RecipeConfig" msgstr "" -#: apps/recipe/models.py:48 -msgid "Title" +#: apps/recipe/models.py:43 +msgid "Hidden" +msgstr "" + +#: apps/recipe/models.py:45 +msgid "Published exclusive" msgstr "" #: apps/recipe/models.py:50 +msgid "Title" +msgstr "" + +#: apps/recipe/models.py:51 msgid "Subtitle" msgstr "" -#: apps/recipe/models.py:57 +#: apps/recipe/models.py:56 msgid "Author" msgstr "" -#: apps/recipe/models.py:58 apps/recipe/models.py:60 +#: apps/recipe/models.py:57 apps/recipe/models.py:58 msgid "Published at" msgstr "" -#: apps/recipe/models.py:61 apps/recipe/models.py:63 +#: apps/recipe/models.py:59 apps/recipe/models.py:60 msgid "Published scheduled at" msgstr "" -#: apps/recipe/models.py:70 +#: apps/recipe/models.py:69 msgid "Recipe" msgstr "" -#: apps/recipe/models.py:71 -msgid "Recipes" -msgstr "" - #: apps/review/apps.py:7 msgid "reviews" msgstr "" -#: apps/review/models.py:37 +#: apps/review/models.py:42 msgid "To investigate" msgstr "" -#: apps/review/models.py:38 +#: apps/review/models.py:43 msgid "To review" msgstr "" -#: apps/review/models.py:39 +#: apps/review/models.py:44 msgid "Ready" msgstr "" -#: apps/review/models.py:45 +#: apps/review/models.py:50 msgid "Reviewer" msgstr "" -#: apps/review/models.py:47 -msgid "text" -msgstr "" - -#: apps/review/models.py:55 -msgid "Review language" -msgstr "" - -#: apps/review/models.py:60 +#: apps/review/models.py:66 msgid "Child review" msgstr "" -#: apps/review/models.py:61 +#: apps/review/models.py:81 msgid "Publish datetime" msgstr "" -#: apps/review/models.py:63 +#: apps/review/models.py:85 msgid "Review published datetime" msgstr "" -#: apps/review/models.py:64 +#: apps/review/models.py:87 msgid "Year of review" msgstr "" -#: apps/review/models.py:72 +#: apps/review/models.py:88 apps/review/models.py:134 +msgid "mark" +msgstr "" + +#: apps/review/models.py:89 +msgid "Priority" +msgstr "" + +#: apps/review/models.py:96 msgid "Review" msgstr "" -#: apps/review/models.py:73 +#: apps/review/models.py:97 msgid "Reviews" msgstr "" +#: apps/review/models.py:109 apps/review/models.py:131 +msgid "review" +msgstr "" + +#: apps/review/models.py:113 +msgid "locale" +msgstr "" + +#: apps/review/models.py:116 +msgid "Text author" +msgstr "" + +#: apps/review/models.py:117 +msgid "Text authors" +msgstr "" + +#: apps/review/models.py:126 +msgid "none" +msgstr "" + +#: apps/review/models.py:127 +msgid "diner" +msgstr "" + +#: apps/review/models.py:128 +msgid "lanch" +msgstr "" + +#: apps/review/models.py:133 +msgid "final comment" +msgstr "" + +#: apps/review/models.py:135 +msgid "attachment" +msgstr "" + +#: apps/review/models.py:139 +msgid "bill" +msgstr "" + +#: apps/review/models.py:147 +msgid "is published" +msgstr "" + +#: apps/review/models.py:150 +msgid "Inquiry" +msgstr "" + +#: apps/review/models.py:151 +msgid "Inquiries" +msgstr "" + +#: apps/review/models.py:159 apps/review/models.py:181 +msgid "inquiry" +msgstr "" + +#: apps/review/models.py:160 +msgid "sub name" +msgstr "" + +#: apps/review/models.py:164 +msgid "dish title" +msgstr "" + +#: apps/review/models.py:167 +msgid "inquiry grid" +msgstr "" + +#: apps/review/models.py:168 +msgid "inquiry grids" +msgstr "" + +#: apps/review/models.py:192 +msgid "inquiry gallery" +msgstr "" + +#: apps/review/models.py:193 +msgid "inquiry galleries" +msgstr "" + #: apps/search_indexes/apps.py:7 msgid "Search indexes" msgstr "" +#: apps/tag/apps.py:7 apps/tag/models.py:185 +msgid "tag" +msgstr "" + +#: apps/tag/models.py:36 apps/tag/models.py:153 +msgid "indexing name" +msgstr "" + +#: apps/tag/models.py:40 +msgid "Category" +msgstr "" + +#: apps/tag/models.py:47 +msgid "old id metadata product" +msgstr "" + +#: apps/tag/models.py:50 apps/tag/models.py:160 apps/translation/apps.py:7 +msgid "Translation" +msgstr "" + +#: apps/tag/models.py:90 +msgid "Chosen tag" +msgstr "" + +#: apps/tag/models.py:91 +msgid "Chosen tags" +msgstr "" + +#: apps/tag/models.py:141 +msgid "string" +msgstr "" + +#: apps/tag/models.py:142 +msgid "list" +msgstr "" + +#: apps/tag/models.py:143 +msgid "integer" +msgstr "" + +#: apps/tag/models.py:144 +msgid "float" +msgstr "" + +#: apps/tag/models.py:145 +msgid "percentage" +msgstr "" + +#: apps/tag/models.py:146 +msgid "boolean" +msgstr "" + +#: apps/tag/models.py:155 +msgid "value type" +msgstr "" + +#: apps/tag/models.py:175 +msgid "Tag category" +msgstr "" + +#: apps/tag/views.py:234 +msgid "Missing required \"items\" parameter" +msgstr "" + +#: apps/tag/views.py:242 +msgid "news/establishments/products" +msgstr "" + #: apps/timetable/apps.py:7 msgid "timetable" msgstr "" -#: apps/timetable/models.py:18 -#: venv/lib/python3.6/site-packages/django/utils/dates.py:6 +#: apps/timetable/models.py:22 msgid "Monday" msgstr "" -#: apps/timetable/models.py:19 -#: venv/lib/python3.6/site-packages/django/utils/dates.py:6 +#: apps/timetable/models.py:23 msgid "Tuesday" msgstr "" -#: apps/timetable/models.py:20 -#: venv/lib/python3.6/site-packages/django/utils/dates.py:6 +#: apps/timetable/models.py:24 msgid "Wednesday" msgstr "" -#: apps/timetable/models.py:21 -#: venv/lib/python3.6/site-packages/django/utils/dates.py:6 +#: apps/timetable/models.py:25 msgid "Thursday" msgstr "" -#: apps/timetable/models.py:22 -#: venv/lib/python3.6/site-packages/django/utils/dates.py:6 +#: apps/timetable/models.py:26 msgid "Friday" msgstr "" -#: apps/timetable/models.py:23 -#: venv/lib/python3.6/site-packages/django/utils/dates.py:7 +#: apps/timetable/models.py:27 msgid "Saturday" msgstr "" -#: apps/timetable/models.py:24 -#: venv/lib/python3.6/site-packages/django/utils/dates.py:7 +#: apps/timetable/models.py:28 msgid "Sunday" msgstr "" -#: apps/timetable/models.py:26 +#: apps/timetable/models.py:31 msgid "Week day" msgstr "" -#: apps/timetable/models.py:28 +#: apps/timetable/models.py:33 msgid "Lunch start time" msgstr "" -#: apps/timetable/models.py:29 +#: apps/timetable/models.py:34 msgid "Lunch end time" msgstr "" -#: apps/timetable/models.py:30 +#: apps/timetable/models.py:35 msgid "Dinner start time" msgstr "" -#: apps/timetable/models.py:31 +#: apps/timetable/models.py:36 msgid "Dinner end time" msgstr "" -#: apps/timetable/models.py:32 +#: apps/timetable/models.py:37 msgid "Opening time" msgstr "" -#: apps/timetable/models.py:33 +#: apps/timetable/models.py:38 msgid "Closed time" msgstr "" -#: apps/timetable/models.py:37 +#: apps/timetable/models.py:42 msgid "Timetable" msgstr "" -#: apps/timetable/models.py:38 +#: apps/timetable/models.py:43 msgid "Timetables" msgstr "" -#: apps/translation/apps.py:7 -msgid "Translation" +#: apps/transfer/apps.py:7 +msgid "Transfer" msgstr "" -#: apps/translation/models.py:24 +#: apps/translation/models.py:29 msgid "Language title" msgstr "" -#: apps/translation/models.py:33 +#: apps/translation/models.py:42 msgid "Language" msgstr "" -#: apps/translation/models.py:51 -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2075 +#: apps/translation/models.py:97 +msgid "Page" +msgstr "" + +#: apps/translation/models.py:99 msgid "Text" msgstr "" -#: apps/translation/models.py:59 apps/translation/models.py:60 +#: apps/translation/models.py:107 apps/translation/models.py:108 msgid "Site interface dictionary" msgstr "" @@ -1124,1968 +2344,149 @@ msgstr "Неправильный логин или пароль." msgid "Item is already in favorites." msgstr "" -#: apps/utils/exceptions.py:144 +#: apps/utils/exceptions.py:143 +msgid "Item is already in carousels." +msgstr "" + +#: apps/utils/exceptions.py:152 msgid "Password reset request is already exists and valid." msgstr "" -#: apps/utils/models.py:21 +#: apps/utils/exceptions.py:161 +msgid "Object has already been added." +msgstr "" + +#: apps/utils/exceptions.py:167 +msgid "Binding object not found." +msgstr "" + +#: apps/utils/exceptions.py:173 +msgid "Removed binding object not found." +msgstr "" + +#: apps/utils/exceptions.py:181 +msgid "Unprocessable entity valid." +msgstr "" + +#: apps/utils/exceptions.py:190 +msgid "Guide element not valid for Guide." +msgstr "" + +#: apps/utils/exceptions.py:199 +msgid "Advertorial already exists for this guide element." +msgstr "" + +#: apps/utils/models.py:29 msgid "Date created" msgstr "" -#: apps/utils/models.py:23 +#: apps/utils/models.py:31 msgid "Date updated" msgstr "" -#: apps/utils/models.py:126 +#: apps/utils/models.py:148 msgid "created by" msgstr "" -#: apps/utils/models.py:130 +#: apps/utils/models.py:152 msgid "modified by" msgstr "" -#: apps/utils/models.py:186 +#: apps/utils/models.py:258 msgid "SVG image" msgstr "" -#: apps/utils/models.py:219 +#: apps/utils/models.py:295 msgid "Mobile" msgstr "" -#: apps/utils/models.py:220 +#: apps/utils/models.py:296 msgid "Web" msgstr "" -#: apps/utils/models.py:221 +#: apps/utils/models.py:297 msgid "All" msgstr "" -#: apps/utils/models.py:224 +#: apps/utils/models.py:300 msgid "Source" msgstr "" -#: project/templates/account/change_email.html:2 +#: apps/utils/models.py:427 +msgid "Is the main image" +msgstr "" + +#: project/templates/account/change_email.html:33 #, python-format msgid "" "You're receiving this email because you want to change email address at " "%(site_name)s." msgstr "" -#: project/templates/account/change_email.html:4 +#: project/templates/account/change_email.html:35 msgid "Please go to the following page for confirmation new email address:" msgstr "" -#: project/templates/account/change_email.html:8 -#: project/templates/account/password_reset_email.html:8 -#: project/templates/authorization/confirm_email.html:7 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_email.html:10 +#: project/templates/account/change_email.html:39 +#: project/templates/account/password_change_email.html:36 +#: project/templates/account/password_reset_email.html:39 +#: project/templates/authorization/confirm_email.html:42 msgid "Thanks for using our site!" msgstr "" -#: project/templates/account/change_email.html:10 -#: project/templates/account/password_reset_email.html:10 -#: project/templates/authorization/confirm_email.html:9 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_email.html:12 +#: project/templates/account/change_email.html:42 +#: project/templates/account/password_change_email.html:39 +#: project/templates/account/password_reset_email.html:41 +#: project/templates/authorization/confirm_email.html:44 #, python-format msgid "The %(site_name)s team" msgstr "" -#: project/templates/account/password_reset_email.html:2 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_email.html:2 +#: project/templates/account/password_change_email.html:34 +#, python-format +msgid "" +"You're receiving this email because your account's password address at " +"%(site_name)s." +msgstr "" + +#: project/templates/account/password_reset_email.html:33 #, python-format msgid "" "You're receiving this email because you requested a password reset for your " "user account at %(site_name)s." msgstr "" -#: project/templates/account/password_reset_email.html:4 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_email.html:4 +#: project/templates/account/password_reset_email.html:35 msgid "Please go to the following page and choose a new password:" msgstr "" -#: project/templates/authorization/confirm_email.html:2 +#: project/templates/authorization/confirm_email.html:34 #, python-format msgid "" "You're receiving this email because you trying to register new account at " "%(site_name)s." msgstr "" -#: project/templates/authorization/confirm_email.html:4 +#: project/templates/authorization/confirm_email.html:36 msgid "Please confirm your email address to complete the registration:" msgstr "" -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/404.html:4 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/404.html:8 -msgid "Page not found" +#: project/templates/authorization/confirm_email.html:39 +msgid "If you use the mobile app, enter the following code in the form:" msgstr "" -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/404.html:10 -msgid "We're sorry, but the requested page could not be found." +#: project/templates/notification/update_email.html:44 +msgid "Follow us" msgstr "" -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/500.html:6 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/app_index.html:10 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/auth/user/change_password.html:19 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:163 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_form.html:22 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_list.html:32 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_confirmation.html:14 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_selected_confirmation.html:15 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/object_history.html:7 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_done.html:7 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_form.html:12 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_complete.html:7 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_confirm.html:7 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_done.html:7 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_form.html:7 -#: venv/lib/python3.6/site-packages/solo/templates/admin/solo/change_form.html:7 -#: venv/lib/python3.6/site-packages/solo/templates/admin/solo/object_history.html:6 -msgid "Home" +#: project/templates/notification/update_email.html:46 +msgid "You can also us on our social network below" msgstr "" -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/500.html:7 -msgid "Server error" +#: project/templates/notification/update_email.html:62 +msgid "This email has been sent to" msgstr "" -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/500.html:11 -msgid "Server error (500)" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/500.html:14 -msgid "Server Error (500)" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/500.html:15 -msgid "" -"There's been an error. It's been reported to the site administrators via " -"email and should be fixed shortly. Thanks for your patience." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/actions.html:7 -msgid "Run the selected action" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/actions.html:7 -msgid "Go" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/actions.html:19 -msgid "Click here to select the objects across all pages" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/actions.html:19 -#, python-format -msgid "Select all %(total_count)s %(module_name)s" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/actions.html:21 -msgid "Clear selection" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/auth/user/add_form.html:7 -msgid "" -"First, enter a username and password. Then, you'll be able to edit more user " -"options." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/auth/user/add_form.html:10 -msgid "Enter a username and password." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/auth/user/change_password.html:31 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/auth/user/change_password.html:75 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:143 -msgid "Change password" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/auth/user/change_password.html:44 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_form.html:65 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_list.html:58 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/login.html:44 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_form.html:31 -msgid "Please correct the error below." -msgid_plural "Please correct the errors below." -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/auth/user/change_password.html:44 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_form.html:65 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_form.html:31 -msgid "Please correct the errors below." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/auth/user/change_password.html:50 -#, python-format -msgid "Enter a new password for the user %(username)s." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/auth/user/change_password.html:60 -msgid "Password" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/auth/user/change_password.html:68 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_form.html:57 -msgid "Password (again)" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/auth/user/change_password.html:69 -msgid "Enter the same password as above, for verification." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:72 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:116 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:119 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base_site.html:9 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/login.html:31 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/login.html:36 -msgid "Django administration" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:81 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:52 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:58 -#, python-format -msgid "Models in the %(name)s application" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:87 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:93 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:143 -msgid "You don't have permission to edit anything." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:138 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:152 -msgid "Documentation" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:147 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:154 -msgid "Log out" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base.html:173 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_list.html:57 -msgid "Close" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/base_site.html:4 -msgid "Django site admin" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_form.html:39 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:65 -msgid "Add" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_form.html:114 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_form.html:116 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/object_history.html:18 -#: venv/lib/python3.6/site-packages/solo/templates/admin/solo/change_form.html:14 -#: venv/lib/python3.6/site-packages/solo/templates/admin/solo/object_history.html:9 -msgid "History" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_form.html:121 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_form.html:123 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/edit_inline/stacked.html:24 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/edit_inline/tabular.html:37 -#: venv/lib/python3.6/site-packages/solo/templates/admin/solo/change_form.html:15 -msgid "View on site" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_list.html:47 -msgid "Filter" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_list.html:81 -#, python-format -msgid "Add %(name)s" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_list.html:143 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/submit_line.html:5 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/submit_line.html:7 -msgid "Save" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_list_results.html:13 -msgid "Remove from sorting" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_list_results.html:16 -#, python-format -msgid "Sorting priority: %(priority_number)s" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/change_list_results.html:17 -msgid "Toggle sorting" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_confirmation.html:25 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/submit_line.html:34 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/submit_line.html:36 -#: venv/lib/python3.6/site-packages/django/forms/formsets.py:375 -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_confirm_delete.html:13 -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_detail.html:38 -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/authorized-token-delete.html:7 -msgid "Delete" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_confirmation.html:34 -#, python-format -msgid "" -"Deleting the %(object_name)s '%(escaped_object)s' would result in deleting " -"related objects, but your account doesn't have permission to delete the " -"following types of objects:" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_confirmation.html:48 -#, python-format -msgid "" -"Deleting the %(object_name)s '%(escaped_object)s' would require deleting the " -"following protected related objects:" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_confirmation.html:62 -#, python-format -msgid "" -"Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"? " -"All of the following related items will be deleted:" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_confirmation.html:70 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_confirmation.html:72 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_selected_confirmation.html:74 -msgid "Yes, I'm sure" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_selected_confirmation.html:23 -msgid "Delete multiple objects" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_selected_confirmation.html:32 -#, python-format -msgid "" -"Deleting the selected %(objects_name)s would result in deleting related " -"objects, but your account doesn't have permission to delete the following " -"types of objects:" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_selected_confirmation.html:46 -#, python-format -msgid "" -"Deleting the selected %(objects_name)s would require deleting the following " -"protected related objects:" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/delete_selected_confirmation.html:60 -#, python-format -msgid "" -"Are you sure you want to delete the selected %(objects_name)s? All of the " -"following objects and their related items will be deleted:" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/edit_inline/tabular.html:22 -msgid "Delete?" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/filter.html:2 -#, python-format -msgid " By %(filter_title)s " -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/includes/object_delete_summary.html:2 -msgid "Summary" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:18 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:21 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:22 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:31 -msgid "Apps" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:37 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:71 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/search_form.html:11 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/search_form.html:13 -msgid "Search" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:42 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/object_history.html:31 -msgid "Action" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:67 -msgid "View" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:69 -#: venv/lib/python3.6/site-packages/django/forms/widgets.py:397 -msgid "Change" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:84 -msgid "Recent actions" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:89 -msgid "None available" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/index.html:115 -msgid "Unknown content" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/invalid_setup.html:5 -msgid "" -"Something's wrong with your database installation. Make sure the appropriate " -"database tables have been created, and make sure the database is readable by " -"the appropriate user." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/login.html:21 -#, python-format -msgid "" -"You are authenticated as %(username)s, but are not authorized to access this " -"page. Would you like to login to a different account?" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/login.html:85 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_complete.html:23 -msgid "Log in" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/login.html:96 -msgid "Forgotten your password or username?" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/object_history.html:29 -msgid "Date/time" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/object_history.html:45 -msgid "" -"This object doesn't have a change history. It probably wasn't added via this " -"admin site." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/pagination.html:19 -msgid "Show all" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/popup_response.html:3 -msgid "Popup closing..." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/related_widget_wrapper.html:9 -#, python-format -msgid "Change selected %(model)s" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/related_widget_wrapper.html:16 -#, python-format -msgid "Add another %(model)s" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/related_widget_wrapper.html:23 -#, python-format -msgid "Delete selected %(model)s" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/search_form.html:4 -#, python-format -msgid "%(counter)s result" -msgid_plural "%(counter)s results" -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/search_form.html:4 -#, python-format -msgid "%(full_result_count)s total" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/submit_line.html:12 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/submit_line.html:14 -msgid "Save as new" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/submit_line.html:19 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/submit_line.html:21 -msgid "Save and add another" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/submit_line.html:26 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/admin/submit_line.html:28 -msgid "Save and continue editing" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/logged_out.html:18 -msgid "Thanks for spending some quality time with the Web site today." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/logged_out.html:20 -msgid "Log in again" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_done.html:10 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_form.html:15 -msgid "Password change" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_done.html:20 -msgid "Your password was changed." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_form.html:37 -msgid "" -"Please enter your old password, for security's sake, and then enter your new " -"password twice so we can verify you typed it in correctly." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_form.html:43 -msgid "Old password" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_change_form.html:66 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_confirm.html:46 -msgid "Change my password" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_complete.html:10 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_done.html:10 -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_form.html:10 -msgid "Password reset" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_complete.html:20 -msgid "Your password has been set. You may go ahead and log in now." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_confirm.html:10 -msgid "Password reset confirmation" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_confirm.html:24 -msgid "" -"Please enter your new password twice so we can verify you typed it in " -"correctly." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_confirm.html:30 -msgid "New password:" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_confirm.html:37 -msgid "Confirm password:" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_confirm.html:55 -msgid "" -"The password reset link was invalid, possibly because it has already been " -"used. Please request a new password reset." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_done.html:19 -msgid "" -"We've emailed you instructions for setting your password. You should be " -"receiving them shortly." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_done.html:21 -msgid "" -"If you don't receive an email, please make sure you've entered the address " -"you registered with, and check your spam folder." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_email.html:8 -msgid "Your username, in case you've forgotten:" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_form.html:23 -msgid "" -"Forgotten your password? Enter your email address below, and we'll email " -"instructions for setting a new one." -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_form.html:29 -msgid "Email address:" -msgstr "" - -#: venv/lib/python3.6/site-packages/bootstrap_admin/templates/registration/password_reset_form.html:38 -msgid "Reset my password" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/contrib/messages/apps.py:7 -msgid "Messages" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/contrib/sitemaps/apps.py:7 -msgid "Site Maps" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/contrib/staticfiles/apps.py:9 -msgid "Static Files" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/contrib/syndication/apps.py:7 -msgid "Syndication" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/paginator.py:45 -msgid "That page number is not an integer" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/paginator.py:47 -msgid "That page number is less than 1" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/paginator.py:52 -msgid "That page contains no results" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:31 -msgid "Enter a valid value." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:102 -#: venv/lib/python3.6/site-packages/django/forms/fields.py:658 -msgid "Enter a valid URL." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:154 -msgid "Enter a valid integer." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:165 -msgid "Enter a valid email address." -msgstr "" - -#. Translators: "letters" means latin letters: a-z and A-Z. -#: venv/lib/python3.6/site-packages/django/core/validators.py:239 -msgid "" -"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:246 -msgid "" -"Enter a valid 'slug' consisting of Unicode letters, numbers, underscores, or " -"hyphens." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:255 -#: venv/lib/python3.6/site-packages/django/core/validators.py:275 -msgid "Enter a valid IPv4 address." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:260 -#: venv/lib/python3.6/site-packages/django/core/validators.py:276 -msgid "Enter a valid IPv6 address." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:270 -#: venv/lib/python3.6/site-packages/django/core/validators.py:274 -msgid "Enter a valid IPv4 or IPv6 address." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:304 -msgid "Enter only digits separated by commas." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:310 -#, python-format -msgid "Ensure this value is %(limit_value)s (it is %(show_value)s)." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:342 -#, python-format -msgid "Ensure this value is less than or equal to %(limit_value)s." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:351 -#, python-format -msgid "Ensure this value is greater than or equal to %(limit_value)s." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:361 -#, python-format -msgid "" -"Ensure this value has at least %(limit_value)d character (it has " -"%(show_value)d)." -msgid_plural "" -"Ensure this value has at least %(limit_value)d characters (it has " -"%(show_value)d)." -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:376 -#, python-format -msgid "" -"Ensure this value has at most %(limit_value)d character (it has " -"%(show_value)d)." -msgid_plural "" -"Ensure this value has at most %(limit_value)d characters (it has " -"%(show_value)d)." -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:395 -#: venv/lib/python3.6/site-packages/django/forms/fields.py:290 -#: venv/lib/python3.6/site-packages/django/forms/fields.py:325 -msgid "Enter a number." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:397 -#, python-format -msgid "Ensure that there are no more than %(max)s digit in total." -msgid_plural "Ensure that there are no more than %(max)s digits in total." -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:402 -#, python-format -msgid "Ensure that there are no more than %(max)s decimal place." -msgid_plural "Ensure that there are no more than %(max)s decimal places." -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:407 -#, python-format -msgid "" -"Ensure that there are no more than %(max)s digit before the decimal point." -msgid_plural "" -"Ensure that there are no more than %(max)s digits before the decimal point." -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:469 -#, python-format -msgid "" -"File extension '%(extension)s' is not allowed. Allowed extensions are: " -"'%(allowed_extensions)s'." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/core/validators.py:521 -msgid "Null characters are not allowed." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/base.py:1162 -#: venv/lib/python3.6/site-packages/django/forms/models.py:756 -msgid "and" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/base.py:1164 -#, python-format -msgid "%(model_name)s with this %(field_labels)s already exists." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:104 -#, python-format -msgid "Value %(value)r is not a valid choice." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:105 -msgid "This field cannot be null." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:106 -msgid "This field cannot be blank." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:107 -#, python-format -msgid "%(model_name)s with this %(field_label)s already exists." -msgstr "" - -#. Translators: The 'lookup_type' is one of 'date', 'year' or 'month'. -#. Eg: "Title must be unique for pub_date year" -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:111 -#, python-format -msgid "" -"%(field_label)s must be unique for %(date_field_label)s %(lookup_type)s." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:128 -#, python-format -msgid "Field of type: %(field_type)s" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:899 -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1766 -msgid "Integer" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:903 -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1764 -#, python-format -msgid "'%(value)s' value must be an integer." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:978 -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1844 -msgid "Big (8 byte) integer" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:990 -#, python-format -msgid "'%(value)s' value must be either True or False." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:991 -#, python-format -msgid "'%(value)s' value must be either True, False, or None." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:993 -msgid "Boolean (Either True or False)" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1034 -#, python-format -msgid "String (up to %(max_length)s)" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1098 -msgid "Comma-separated integers" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1147 -#, python-format -msgid "" -"'%(value)s' value has an invalid date format. It must be in YYYY-MM-DD " -"format." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1149 -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1292 -#, python-format -msgid "" -"'%(value)s' value has the correct format (YYYY-MM-DD) but it is an invalid " -"date." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1152 -msgid "Date (without time)" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1290 -#, python-format -msgid "" -"'%(value)s' value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[." -"uuuuuu]][TZ] format." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1294 -#, python-format -msgid "" -"'%(value)s' value has the correct format (YYYY-MM-DD HH:MM[:ss[.uuuuuu]]" -"[TZ]) but it is an invalid date/time." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1298 -msgid "Date (with time)" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1446 -#, python-format -msgid "'%(value)s' value must be a decimal number." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1448 -msgid "Decimal number" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1587 -#, python-format -msgid "" -"'%(value)s' value has an invalid format. It must be in [DD] [HH:[MM:]]ss[." -"uuuuuu] format." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1590 -msgid "Duration" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1640 -msgid "Email address" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1663 -msgid "File path" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1729 -#, python-format -msgid "'%(value)s' value must be a float." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1731 -msgid "Floating point number" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1860 -msgid "IPv4 address" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1971 -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1972 -#, python-format -msgid "'%(value)s' value must be either None, True or False." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:1974 -msgid "Boolean (Either True, False or None)" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2009 -msgid "Positive integer" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2022 -msgid "Positive small integer" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2036 -#, python-format -msgid "Slug (up to %(max_length)s)" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2068 -msgid "Small integer" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2103 -#, python-format -msgid "" -"'%(value)s' value has an invalid format. It must be in HH:MM[:ss[.uuuuuu]] " -"format." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2105 -#, python-format -msgid "" -"'%(value)s' value has the correct format (HH:MM[:ss[.uuuuuu]]) but it is an " -"invalid time." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2108 -msgid "Time" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2256 -msgid "Raw binary data" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2306 -#, python-format -msgid "'%(value)s' is not a valid UUID." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py:2308 -msgid "Universally unique identifier" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/files.py:221 -msgid "File" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/related.py:778 -#, python-format -msgid "%(model)s instance with %(field)s %(value)r does not exist." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/related.py:780 -msgid "Foreign Key (type determined by related field)" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/related.py:1007 -msgid "One-to-one relationship" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/related.py:1057 -#, python-format -msgid "%(from)s-%(to)s relationship" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/related.py:1058 -#, python-format -msgid "%(from)s-%(to)s relationships" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/db/models/fields/related.py:1100 -msgid "Many-to-many relationship" -msgstr "" - -#. Translators: If found as last label character, these punctuation -#. characters will prevent the default label_suffix to be appended to the label -#: venv/lib/python3.6/site-packages/django/forms/boundfield.py:146 -msgid ":?.!" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:245 -msgid "Enter a whole number." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:396 -#: venv/lib/python3.6/site-packages/django/forms/fields.py:1126 -msgid "Enter a valid date." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:420 -#: venv/lib/python3.6/site-packages/django/forms/fields.py:1127 -msgid "Enter a valid time." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:442 -msgid "Enter a valid date/time." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:471 -msgid "Enter a valid duration." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:472 -#, python-brace-format -msgid "The number of days must be between {min_days} and {max_days}." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:532 -msgid "No file was submitted. Check the encoding type on the form." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:533 -msgid "No file was submitted." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:534 -msgid "The submitted file is empty." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:536 -#, python-format -msgid "Ensure this filename has at most %(max)d character (it has %(length)d)." -msgid_plural "" -"Ensure this filename has at most %(max)d characters (it has %(length)d)." -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:539 -msgid "Please either submit a file or check the clear checkbox, not both." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:600 -msgid "" -"Upload a valid image. The file you uploaded was either not an image or a " -"corrupted image." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:762 -#: venv/lib/python3.6/site-packages/django/forms/fields.py:852 -#: venv/lib/python3.6/site-packages/django/forms/models.py:1270 -#, python-format -msgid "Select a valid choice. %(value)s is not one of the available choices." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:853 -#: venv/lib/python3.6/site-packages/django/forms/fields.py:968 -#: venv/lib/python3.6/site-packages/django/forms/models.py:1269 -msgid "Enter a list of values." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:969 -msgid "Enter a complete value." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/fields.py:1185 -msgid "Enter a valid UUID." -msgstr "" - -#. Translators: This is the default suffix added to form field labels -#: venv/lib/python3.6/site-packages/django/forms/forms.py:86 -msgid ":" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/forms.py:212 -#, python-format -msgid "(Hidden field %(name)s) %(error)s" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/formsets.py:91 -msgid "ManagementForm data is missing or has been tampered with" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/formsets.py:338 -#, python-format -msgid "Please submit %d or fewer forms." -msgid_plural "Please submit %d or fewer forms." -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/forms/formsets.py:345 -#, python-format -msgid "Please submit %d or more forms." -msgid_plural "Please submit %d or more forms." -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/forms/formsets.py:371 -#: venv/lib/python3.6/site-packages/django/forms/formsets.py:373 -msgid "Order" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/models.py:751 -#, python-format -msgid "Please correct the duplicate data for %(field)s." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/models.py:755 -#, python-format -msgid "Please correct the duplicate data for %(field)s, which must be unique." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/models.py:761 -#, python-format -msgid "" -"Please correct the duplicate data for %(field_name)s which must be unique " -"for the %(lookup)s in %(date_field)s." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/models.py:770 -msgid "Please correct the duplicate values below." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/models.py:1091 -msgid "The inline value did not match the parent instance." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/models.py:1158 -msgid "Select a valid choice. That choice is not one of the available choices." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/models.py:1272 -#, python-format -msgid "\"%(pk)s\" is not a valid value." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/utils.py:162 -#, python-format -msgid "" -"%(datetime)s couldn't be interpreted in time zone %(current_timezone)s; it " -"may be ambiguous or it may not exist." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/widgets.py:395 -msgid "Clear" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/widgets.py:396 -msgid "Currently" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/widgets.py:711 -msgid "Unknown" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/widgets.py:712 -msgid "Yes" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/forms/widgets.py:713 -msgid "No" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/template/defaultfilters.py:788 -msgid "yes,no,maybe" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/template/defaultfilters.py:817 -#: venv/lib/python3.6/site-packages/django/template/defaultfilters.py:834 -#, python-format -msgid "%(size)d byte" -msgid_plural "%(size)d bytes" -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/template/defaultfilters.py:836 -#, python-format -msgid "%s KB" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/template/defaultfilters.py:838 -#, python-format -msgid "%s MB" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/template/defaultfilters.py:840 -#, python-format -msgid "%s GB" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/template/defaultfilters.py:842 -#, python-format -msgid "%s TB" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/template/defaultfilters.py:844 -#, python-format -msgid "%s PB" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dateformat.py:62 -msgid "p.m." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dateformat.py:63 -msgid "a.m." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dateformat.py:68 -msgid "PM" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dateformat.py:69 -msgid "AM" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dateformat.py:150 -msgid "midnight" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dateformat.py:152 -msgid "noon" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:10 -msgid "Mon" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:10 -msgid "Tue" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:10 -msgid "Wed" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:10 -msgid "Thu" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:10 -msgid "Fri" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:11 -msgid "Sat" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:11 -msgid "Sun" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:14 -msgid "January" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:14 -msgid "February" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:14 -msgid "March" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:14 -msgid "April" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:14 -msgid "May" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:14 -msgid "June" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:15 -msgid "July" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:15 -msgid "August" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:15 -msgid "September" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:15 -msgid "October" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:15 -msgid "November" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:16 -msgid "December" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:19 -msgid "jan" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:19 -msgid "feb" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:19 -msgid "mar" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:19 -msgid "apr" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:19 -msgid "may" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:19 -msgid "jun" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:20 -msgid "jul" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:20 -msgid "aug" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:20 -msgid "sep" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:20 -msgid "oct" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:20 -msgid "nov" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:20 -msgid "dec" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:23 -msgctxt "abbrev. month" -msgid "Jan." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:24 -msgctxt "abbrev. month" -msgid "Feb." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:25 -msgctxt "abbrev. month" -msgid "March" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:26 -msgctxt "abbrev. month" -msgid "April" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:27 -msgctxt "abbrev. month" -msgid "May" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:28 -msgctxt "abbrev. month" -msgid "June" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:29 -msgctxt "abbrev. month" -msgid "July" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:30 -msgctxt "abbrev. month" -msgid "Aug." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:31 -msgctxt "abbrev. month" -msgid "Sept." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:32 -msgctxt "abbrev. month" -msgid "Oct." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:33 -msgctxt "abbrev. month" -msgid "Nov." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:34 -msgctxt "abbrev. month" -msgid "Dec." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:37 -msgctxt "alt. month" -msgid "January" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:38 -msgctxt "alt. month" -msgid "February" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:39 -msgctxt "alt. month" -msgid "March" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:40 -msgctxt "alt. month" -msgid "April" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:41 -msgctxt "alt. month" -msgid "May" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:42 -msgctxt "alt. month" -msgid "June" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:43 -msgctxt "alt. month" -msgid "July" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:44 -msgctxt "alt. month" -msgid "August" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:45 -msgctxt "alt. month" -msgid "September" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:46 -msgctxt "alt. month" -msgid "October" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:47 -msgctxt "alt. month" -msgid "November" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/dates.py:48 -msgctxt "alt. month" -msgid "December" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/ipv6.py:8 -msgid "This is not a valid IPv6 address." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/text.py:67 -#, python-format -msgctxt "String to return when truncating text" -msgid "%(truncated_text)s…" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/text.py:233 -msgid "or" -msgstr "" - -#. Translators: This string is used as a separator between list elements -#: venv/lib/python3.6/site-packages/django/utils/text.py:252 -#: venv/lib/python3.6/site-packages/django/utils/timesince.py:83 -msgid ", " -msgstr "" - -#: venv/lib/python3.6/site-packages/django/utils/timesince.py:9 -#, python-format -msgid "%d year" -msgid_plural "%d years" -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/utils/timesince.py:10 -#, python-format -msgid "%d month" -msgid_plural "%d months" -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/utils/timesince.py:11 -#, python-format -msgid "%d week" -msgid_plural "%d weeks" -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/utils/timesince.py:12 -#, python-format -msgid "%d day" -msgid_plural "%d days" -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/utils/timesince.py:13 -#, python-format -msgid "%d hour" -msgid_plural "%d hours" -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/utils/timesince.py:14 -#, python-format -msgid "%d minute" -msgid_plural "%d minutes" -msgstr[0] "" -msgstr[1] "" - -#: venv/lib/python3.6/site-packages/django/utils/timesince.py:72 -msgid "0 minutes" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/csrf.py:110 -msgid "Forbidden" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/csrf.py:111 -msgid "CSRF verification failed. Request aborted." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/csrf.py:115 -msgid "" -"You are seeing this message because this HTTPS site requires a 'Referer " -"header' to be sent by your Web browser, but none was sent. This header is " -"required for security reasons, to ensure that your browser is not being " -"hijacked by third parties." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/csrf.py:120 -msgid "" -"If you have configured your browser to disable 'Referer' headers, please re-" -"enable them, at least for this site, or for HTTPS connections, or for 'same-" -"origin' requests." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/csrf.py:124 -msgid "" -"If you are using the tag or " -"including the 'Referrer-Policy: no-referrer' header, please remove them. The " -"CSRF protection requires the 'Referer' header to do strict referer checking. " -"If you're concerned about privacy, use alternatives like for links to third-party sites." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/csrf.py:132 -msgid "" -"You are seeing this message because this site requires a CSRF cookie when " -"submitting forms. This cookie is required for security reasons, to ensure " -"that your browser is not being hijacked by third parties." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/csrf.py:137 -msgid "" -"If you have configured your browser to disable cookies, please re-enable " -"them, at least for this site, or for 'same-origin' requests." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/csrf.py:142 -msgid "More information is available with DEBUG=True." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/dates.py:41 -msgid "No year specified" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/dates.py:61 -#: venv/lib/python3.6/site-packages/django/views/generic/dates.py:111 -#: venv/lib/python3.6/site-packages/django/views/generic/dates.py:208 -msgid "Date out of range" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/dates.py:90 -msgid "No month specified" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/dates.py:142 -msgid "No day specified" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/dates.py:188 -msgid "No week specified" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/dates.py:338 -#: venv/lib/python3.6/site-packages/django/views/generic/dates.py:367 -#, python-format -msgid "No %(verbose_name_plural)s available" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/dates.py:589 -#, python-format -msgid "" -"Future %(verbose_name_plural)s not available because %(class_name)s." -"allow_future is False." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/dates.py:623 -#, python-format -msgid "Invalid date string '%(datestr)s' given format '%(format)s'" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/detail.py:54 -#, python-format -msgid "No %(verbose_name)s found matching the query" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/list.py:67 -msgid "Page is not 'last', nor can it be converted to an int." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/list.py:72 -#, python-format -msgid "Invalid page (%(page_number)s): %(message)s" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/generic/list.py:154 -#, python-format -msgid "Empty list and '%(class_name)s.allow_empty' is False." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/static.py:40 -msgid "Directory indexes are not allowed here." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/static.py:42 -#, python-format -msgid "\"%(path)s\" does not exist" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/static.py:80 -#, python-format -msgid "Index of %(directory)s" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/templates/default_urlconf.html:6 -msgid "Django: the Web framework for perfectionists with deadlines." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/templates/default_urlconf.html:345 -#, python-format -msgid "" -"View release notes for Django %(version)s" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/templates/default_urlconf.html:367 -msgid "The install worked successfully! Congratulations!" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/templates/default_urlconf.html:368 -#, python-format -msgid "" -"You are seeing this page because DEBUG=True is in your settings file and you have not configured any " -"URLs." -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/templates/default_urlconf.html:383 -msgid "Django Documentation" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/templates/default_urlconf.html:384 -msgid "Topics, references, & how-to's" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/templates/default_urlconf.html:395 -msgid "Tutorial: A Polling App" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/templates/default_urlconf.html:396 -msgid "Get started with Django" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/templates/default_urlconf.html:407 -msgid "Django Community" -msgstr "" - -#: venv/lib/python3.6/site-packages/django/views/templates/default_urlconf.html:408 -msgid "Connect, get help, or contribute" -msgstr "" - -#: venv/lib/python3.6/site-packages/easy_select2/forms.py:7 -msgid "" -"Hold down \"Control\", or \"Command\" on a Mac, to select more than one." -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/admin.py:64 -#, python-format -msgid "Some messages were sent: %s" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/admin.py:66 -#, python-format -msgid "All messages were sent: %s" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/admin.py:72 -#, python-format -msgid "Some messages failed to send. %d devices were marked as inactive." -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/admin.py:80 -msgid "Send test notification" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/admin.py:85 -msgid "Send test notification in bulk" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/admin.py:90 -msgid "Send test data message" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/admin.py:96 -msgid "Send test data message in bulk" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/admin.py:101 -msgid "Enable selected devices" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/admin.py:106 -msgid "Disable selected devices" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/apps.py:7 -msgid "FCM Django" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/fields.py:52 -msgid "Enter a valid hexadecimal number" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/models.py:19 -msgid "Is active" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/models.py:20 -msgid "Inactive devices will not be sent notifications" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/models.py:25 -msgid "Creation date" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/models.py:161 -msgid "Device ID" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/models.py:162 -msgid "Unique device identifier" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/models.py:165 -msgid "Registration token" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/models.py:171 -#: venv/lib/python3.6/site-packages/fcm_django/models.py:255 -msgid "FCM device" -msgstr "" - -#: venv/lib/python3.6/site-packages/fcm_django/models.py:256 -msgid "FCM devices" -msgstr "" - -#: venv/lib/python3.6/site-packages/kombu/transport/qpid.py:1301 -#, python-format -msgid "Attempting to connect to qpid with SASL mechanism %s" -msgstr "" - -#: venv/lib/python3.6/site-packages/kombu/transport/qpid.py:1306 -#, python-format -msgid "Connected to qpid with SASL mechanism %s" -msgstr "" - -#: venv/lib/python3.6/site-packages/kombu/transport/qpid.py:1324 -#, python-format -msgid "Unable to connect to qpid with SASL mechanism %s" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/models.py:41 -msgid "Confidential" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/models.py:42 -msgid "Public" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/models.py:50 -msgid "Authorization code" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/models.py:51 -msgid "Implicit" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/models.py:52 -msgid "Resource owner password-based" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/models.py:53 -msgid "Client credentials" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/models.py:67 -msgid "Allowed URIs list, space separated" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/models.py:143 -#, python-brace-format -msgid "Unauthorized redirect scheme: {scheme}" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/models.py:148 -#, python-brace-format -msgid "redirect_uris cannot be empty with grant_type {grant_type}" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/oauth2_validators.py:166 -msgid "The access token is invalid." -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/oauth2_validators.py:171 -msgid "The access token has expired." -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/oauth2_validators.py:176 -msgid "The access token is valid but does not have enough scope." -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_confirm_delete.html:6 -msgid "Are you sure to delete the application" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_confirm_delete.html:12 -msgid "Cancel" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_detail.html:10 -msgid "Client id" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_detail.html:15 -msgid "Client secret" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_detail.html:20 -msgid "Client type" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_detail.html:25 -msgid "Authorization Grant Type" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_detail.html:30 -msgid "Redirect Uris" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_detail.html:36 -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_form.html:35 -msgid "Go Back" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_detail.html:37 -msgid "Edit" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_form.html:9 -msgid "Edit application" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_list.html:6 -msgid "Your applications" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_list.html:16 -msgid "No applications defined" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_list.html:16 -msgid "Click here" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_list.html:16 -msgid "if you want to register a new one" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/application_registration_form.html:5 -msgid "Register a new application" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/authorize.html:8 -msgid "Authorize" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/authorize.html:17 -msgid "Application requires following permissions" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/authorized-token-delete.html:6 -msgid "Are you sure you want to delete this token?" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/authorized-tokens.html:6 -msgid "Tokens" -msgstr "" - -#: venv/lib/python3.6/site-packages/oauth2_provider/templates/oauth2_provider/authorized-tokens.html:19 -msgid "There are no authorized tokens yet." -msgstr "" - -#: venv/lib/python3.6/site-packages/solo/admin.py:53 -#, python-format -msgid "%(obj)s was changed successfully." -msgstr "" - -#: venv/lib/python3.6/site-packages/solo/admin.py:55 -msgid "You may edit it again below." -msgstr "" - -#: venv/lib/python3.6/site-packages/solo/templatetags/solo_tags.py:22 -#, python-format -msgid "" -"Templatetag requires the model dotted path: 'app_label.ModelName'. Received " -"'%s'." -msgstr "" - -#: venv/lib/python3.6/site-packages/solo/templatetags/solo_tags.py:28 -#, python-format -msgid "" -"Could not get the model name '%(model)s' from the application named '%(app)s'" +#: project/templates/notification/update_email.html:63 +msgid "click here to unsubscribe" msgstr "" From e067e8e793eda39c5910411d76c73d7cea50bf4b Mon Sep 17 00:00:00 2001 From: dormantman Date: Tue, 28 Jan 2020 18:29:02 +0300 Subject: [PATCH 069/101] Added menu upload files --- apps/establishment/models.py | 59 ++++--------- apps/establishment/serializers/back.py | 94 ++++++++++---------- apps/establishment/serializers/common.py | 56 ++++++++++-- apps/establishment/urls/back.py | 6 +- apps/establishment/views/back.py | 105 ++++++++++++----------- apps/utils/methods.py | 11 ++- apps/utils/models.py | 33 ++++++- 7 files changed, 210 insertions(+), 154 deletions(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index b1adf435..83a7c5e8 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -30,10 +30,13 @@ from main.models import Award, Currency from review.models import Review from tag.models import Tag from utils.methods import transform_into_readable_str -from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin, - TranslatedFieldsMixin, BaseAttributes, GalleryMixin, - IntermediateGalleryModelMixin, HasTagsMixin, - FavoritesMixin, TypeDefaultImageMixin) +from utils.models import ( + ProjectBaseMixin, TJSONField, URLImageMixin, + TranslatedFieldsMixin, BaseAttributes, GalleryMixin, + IntermediateGalleryModelMixin, HasTagsMixin, + FavoritesMixin, TypeDefaultImageMixin, FileMixin, + ImageMixin, +) # todo: establishment type&subtypes check @@ -1272,6 +1275,7 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes): STR_FIELD_NAME = 'category' + name = models.CharField(_('name'), max_length=255, default='') category = TJSONField( blank=True, null=True, default=None, verbose_name=_('category'), help_text='{"en-GB":"some text"}') @@ -1282,9 +1286,14 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes): schedule = models.ManyToManyField( to='timetable.Timetable', blank=True, - verbose_name=_('Establishment schedule'), - related_name='menus', + verbose_name=_('Menu schedule'), ) + uploads = models.ManyToManyField( + to='MenuFiles', + blank=True, + verbose_name=_('Menu files'), + ) + old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None) objects = MenuQuerySet.as_manager() @@ -1295,43 +1304,11 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes): ordering = ('-created',) -class MenuGallery(IntermediateGalleryModelMixin): - menu = models.ForeignKey( - Menu, - null=True, - related_name='menu_gallery', - on_delete=models.CASCADE, - verbose_name=_('menu'), - ) - image = models.ForeignKey( - 'gallery.Image', - null=True, - related_name='menu_gallery', - on_delete=models.CASCADE, - verbose_name=_('image'), - ) - - class Meta: - """Meta class.""" - verbose_name = _('menu gallery') - verbose_name_plural = _('menu galleries') - unique_together = (('menu', 'is_main'), ('menu', 'image')) - - -class MenuUploads(BaseAttributes): +class MenuFiles(FileMixin, BaseAttributes): """Menu files""" - menu = models.ForeignKey( - Menu, - verbose_name=_('menu'), - on_delete=models.CASCADE, - related_name='menu_uploads', - ) - title = models.CharField(_('title'), max_length=255, default='') - file = models.FileField( - _('File'), - validators=[FileExtensionValidator(allowed_extensions=('doc', 'docx', 'pdf')), ], - ) + name = models.CharField(_('name'), max_length=255, default='') + type = models.CharField(_('type'), max_length=65, default='') class Meta: verbose_name = _('menu upload') diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 8d02f252..e3adb490 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -639,50 +639,50 @@ class MenuDishesRUDSerializers(ProjectModelSerializer): ] -class MenuGallerySerializer(serializers.ModelSerializer): - """Serializer class for model MenuGallery.""" - - class Meta: - """Meta class""" - - model = models.MenuGallery - fields = [ - 'id', - 'is_main', - ] - - @property - def request_kwargs(self): - """Get url kwargs from request.""" - return self.context.get('request').parser_context.get('kwargs') - - def create(self, validated_data): - menu_pk = self.request_kwargs.get('pk') - image_id = self.request_kwargs.get('image_id') - qs = models.MenuGallery.objects.filter(image_id=image_id, menu_id=menu_pk) - instance = qs.first() - if instance: - qs.update(**validated_data) - return instance - return super().create(validated_data) - - def validate(self, attrs): - """Override validate method.""" - menu_pk = self.request_kwargs.get('pk') - image_id = self.request_kwargs.get('image_id') - - menu_qs = models.Menu.objects.filter(pk=menu_pk) - image_qs = Image.objects.filter(id=image_id) - - if not menu_qs.exists(): - raise serializers.ValidationError({'detail': _('Menu not found')}) - if not image_qs.exists(): - raise serializers.ValidationError({'detail': _('Image not found')}) - - menu = menu_qs.first() - image = image_qs.first() - - attrs['menu'] = menu - attrs['image'] = image - - return attrs +# class MenuGallerySerializer(serializers.ModelSerializer): +# """Serializer class for model MenuGallery.""" +# +# class Meta: +# """Meta class""" +# +# model = models.MenuGallery +# fields = [ +# 'id', +# 'is_main', +# ] +# +# @property +# def request_kwargs(self): +# """Get url kwargs from request.""" +# return self.context.get('request').parser_context.get('kwargs') +# +# def create(self, validated_data): +# menu_pk = self.request_kwargs.get('pk') +# image_id = self.request_kwargs.get('image_id') +# qs = models.MenuGallery.objects.filter(image_id=image_id, menu_id=menu_pk) +# instance = qs.first() +# if instance: +# qs.update(**validated_data) +# return instance +# return super().create(validated_data) +# +# def validate(self, attrs): +# """Override validate method.""" +# menu_pk = self.request_kwargs.get('pk') +# image_id = self.request_kwargs.get('image_id') +# +# menu_qs = models.Menu.objects.filter(pk=menu_pk) +# image_qs = Image.objects.filter(id=image_id) +# +# if not menu_qs.exists(): +# raise serializers.ValidationError({'detail': _('Menu not found')}) +# if not image_qs.exists(): +# raise serializers.ValidationError({'detail': _('Image not found')}) +# +# menu = menu_qs.first() +# image = image_qs.first() +# +# attrs['menu'] = menu +# attrs['image'] = image +# +# return attrs diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 5d53eec8..4bb1a8d4 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -9,18 +9,25 @@ from rest_framework import serializers from comment import models as comment_models from comment.serializers import common as comment_serializers from establishment import models -from location.serializers import AddressBaseSerializer, CityBaseSerializer, AddressDetailSerializer, \ - CityShortSerializer -from location.serializers import EstablishmentWineRegionBaseSerializer, \ - EstablishmentWineOriginBaseSerializer +from establishment.models import Establishment +from location.serializers import ( + AddressBaseSerializer, CityBaseSerializer, AddressDetailSerializer, + CityShortSerializer, +) +from location.serializers import ( + EstablishmentWineRegionBaseSerializer, + EstablishmentWineOriginBaseSerializer, +) from main.serializers import AwardSerializer, CurrencySerializer from review.serializers import ReviewShortSerializer from tag.serializers import TagBaseSerializer from timetable.serialziers import ScheduleRUDSerializer from utils import exceptions as utils_exceptions from utils.serializers import ImageBaseSerializer, CarouselCreateSerializer -from utils.serializers import (ProjectModelSerializer, TranslatedField, - FavoritesCreateSerializer) +from utils.serializers import ( + ProjectModelSerializer, TranslatedField, + FavoritesCreateSerializer, +) logger = logging.getLogger(__name__) @@ -71,19 +78,50 @@ class PlateSerializer(ProjectModelSerializer): class MenuSerializers(ProjectModelSerializer): - plates = PlateSerializer(read_only=True, many=True, source='plate_set') + name = serializers.CharField() + establishment_id = serializers.PrimaryKeyRelatedField(queryset=models.Establishment.objects.all()) + establishment_slug = serializers.CharField(read_only=True, source='establishment.slug') + price = serializers.IntegerField(read_only=True, source='establishment.price_level', required=False) + drinks_included = serializers.BooleanField(source='is_drinks_included', required=FavoritesCreateSerializer) + schedules = ScheduleRUDSerializer(many=True, allow_null=True, required=False) + uploads = serializers.FileField(allow_null=True, required=False) category_translated = serializers.CharField(read_only=True) class Meta: model = models.Menu fields = [ 'id', + 'name', + 'establishment', + 'establishment_id', + 'establishment_slug', + 'price', + 'drinks_included', + 'schedules', + 'uploads', 'category', 'category_translated', - 'plates', - 'establishment' ] + def create(self, validated_data): + print(validated_data, '\n\n\n\n\n') + establishment = models.Establishment.objects.get(pk=validated_data.pop('establishment')) + validated_data['establishment'] = establishment['id'] + instance = models.Menu.objects.create(**validated_data) + return instance + +''' +{ + "name": "Menu test", + "establishment_id": 1, + "price": 1, + "drinks_included": true, + "schedules": [], + "uploads": null, + "category": null +} +''' + class MenuRUDSerializers(ProjectModelSerializer): plates = PlateSerializer(read_only=True, many=True, source='plate_set') diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index d5173942..6db9d07a 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -32,9 +32,9 @@ urlpatterns = [ name='establishment-admin-list'), path('menus/dishes/', views.MenuDishesListCreateView.as_view(), name='menu-dishes-list'), path('menus/dishes//', views.MenuDishesRUDView.as_view(), name='menu-dishes-rud'), - path('menus/dishes//gallery/', views.MenuGalleryListView.as_view(), name='menu-dishes-gallery-list'), - path('menus/dishes//gallery//', views.MenuGalleryCreateDestroyView.as_view(), - name='menu-dishes-gallery-create-destroy'), + # path('menus/dishes//gallery/', views.MenuGalleryListView.as_view(), name='menu-dishes-gallery-list'), + # path('menus/dishes//gallery//', views.MenuGalleryCreateDestroyView.as_view(), + # name='menu-dishes-gallery-create-destroy'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus//', views.MenuRUDView.as_view(), name='menu-rud'), path('plates/', views.PlateListCreateView.as_view(), name='plates'), diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index d745f5e9..b56ebf10 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -125,6 +125,9 @@ class MenuListCreateView(generics.ListCreateAPIView): 'establishment__slug', ) + def get_queryset(self): + return super().get_queryset().prefetch_related('establishment') + class MenuRUDView(generics.RetrieveUpdateDestroyAPIView): """Menu RUD view.""" @@ -464,54 +467,54 @@ class MenuDishesRUDView(generics.RetrieveUpdateDestroyAPIView): permission_classes = [IsWineryReviewer | IsEstablishmentManager] -class MenuGalleryListView(generics.ListAPIView): - """Resource for returning gallery for menu for back-office users.""" - serializer_class = serializers.ImageBaseSerializer - permission_classes = [IsWineryReviewer | IsEstablishmentManager] - queryset = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() - - def get_object(self): - """Override get_object method.""" - qs = super(MenuGalleryListView, self).get_queryset() - menu = get_object_or_404(qs, pk=self.kwargs.get('pk')) - - # May raise a permission denied - # self.check_object_permissions(self.request, menu) - - return menu - - def get_queryset(self): - """Override get_queryset method.""" - return self.get_object().crop_gallery - - -class MenuGalleryCreateDestroyView(CreateDestroyGalleryViewMixin): - """Resource for a create gallery for menu for back-office users.""" - serializer_class = serializers.MenuGallerySerializer - permission_classes = [IsWineryReviewer | IsEstablishmentManager] - - def get_queryset(self): - """Override get_queryset method.""" - qs = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() - return qs - - def create(self, request, *args, **kwargs): - _ = super().create(request, *args, **kwargs) - news_qs = self.filter_queryset(self.get_queryset()) - return response.Response( - data=serializers.MenuDishesRUDSerializers(get_object_or_404(news_qs, pk=kwargs.get('pk'))).data - ) - - def get_object(self): - """ - Returns the object the view is displaying. - """ - menu_qs = self.filter_queryset(self.get_queryset()) - - menu = get_object_or_404(menu_qs, pk=self.kwargs.get('pk')) - gallery = get_object_or_404(menu.menu_gallery, image_id=self.kwargs.get('image_id')) - - # May raise a permission denied - self.check_object_permissions(self.request, gallery) - - return gallery +# class MenuGalleryListView(generics.ListAPIView): +# """Resource for returning gallery for menu for back-office users.""" +# serializer_class = serializers.ImageBaseSerializer +# permission_classes = [IsWineryReviewer | IsEstablishmentManager] +# queryset = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() +# +# def get_object(self): +# """Override get_object method.""" +# qs = super(MenuGalleryListView, self).get_queryset() +# menu = get_object_or_404(qs, pk=self.kwargs.get('pk')) +# +# # May raise a permission denied +# # self.check_object_permissions(self.request, menu) +# +# return menu +# +# def get_queryset(self): +# """Override get_queryset method.""" +# return self.get_object().crop_gallery +# +# +# class MenuGalleryCreateDestroyView(CreateDestroyGalleryViewMixin): +# """Resource for a create gallery for menu for back-office users.""" +# serializer_class = serializers.MenuGallerySerializer +# permission_classes = [IsWineryReviewer | IsEstablishmentManager] +# +# def get_queryset(self): +# """Override get_queryset method.""" +# qs = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() +# return qs +# +# def create(self, request, *args, **kwargs): +# _ = super().create(request, *args, **kwargs) +# news_qs = self.filter_queryset(self.get_queryset()) +# return response.Response( +# data=serializers.MenuDishesRUDSerializers(get_object_or_404(news_qs, pk=kwargs.get('pk'))).data +# ) +# +# def get_object(self): +# """ +# Returns the object the view is displaying. +# """ +# menu_qs = self.filter_queryset(self.get_queryset()) +# +# menu = get_object_or_404(menu_qs, pk=self.kwargs.get('pk')) +# gallery = get_object_or_404(menu.menu_gallery, image_id=self.kwargs.get('image_id')) +# +# # May raise a permission denied +# self.check_object_permissions(self.request, gallery) +# +# return gallery diff --git a/apps/utils/methods.py b/apps/utils/methods.py index 58cc3f52..839105e2 100644 --- a/apps/utils/methods.py +++ b/apps/utils/methods.py @@ -6,7 +6,7 @@ import string from collections import namedtuple from functools import reduce from io import BytesIO - +import pathlib import requests from django.conf import settings from django.contrib.contenttypes.models import ContentType @@ -69,6 +69,15 @@ def username_random(): ) +def file_path(instance, filename): + """Determine file path method.""" + filename = '%s.%s' % (generate_code(), pathlib.Path(filename).suffix.lstrip('.')) + return 'files/%s/%s/%s' % ( + instance._meta.model_name, + datetime.now().strftime(settings.REST_DATE_FORMAT), + filename) + + def image_path(instance, filename): """Determine avatar path method.""" filename = '%s.jpeg' % generate_code() diff --git a/apps/utils/models.py b/apps/utils/models.py index d58a1bbc..281c57ca 100644 --- a/apps/utils/models.py +++ b/apps/utils/models.py @@ -8,6 +8,7 @@ from django.contrib.gis.db import models from django.contrib.postgres.aggregates import ArrayAgg from django.contrib.postgres.fields import JSONField from django.contrib.postgres.fields.jsonb import KeyTextTransform +from django.core.validators import FileExtensionValidator from django.utils import timezone from django.utils.html import mark_safe from django.utils.translation import ugettext_lazy as _, get_language @@ -16,7 +17,7 @@ from sorl.thumbnail import get_thumbnail from sorl.thumbnail.fields import ImageField as SORLImageField from configuration.models import TranslationSettings -from utils.methods import image_path, svg_image_path +from utils.methods import image_path, svg_image_path, file_path from utils.validators import svg_image_validator logger = logging.getLogger(__name__) @@ -86,6 +87,7 @@ def translate_field(self, field_name, toggle_field_name=None): return None return value return None + return translate @@ -159,6 +161,33 @@ class BaseAttributes(ProjectBaseMixin): abstract = True +class FileMixin(models.Model): + """File model.""" + + file = models.FileField(upload_to=file_path, + blank=True, null=True, default=None, + verbose_name=_('File'), + validators=[FileExtensionValidator( + allowed_extensions=('jpg', 'jpeg', 'png', 'doc', 'docx', 'pdf') + )]) + + class Meta: + """Meta class.""" + + abstract = True + + def get_file_url(self): + """Get file url.""" + return self.file.url if self.file else None + + def get_full_file_url(self, request): + """Get full file url""" + if self.file and exists(self.file.path): + return request.build_absolute_uri(self.file.url) + else: + return None + + class ImageMixin(models.Model): """Avatar model.""" @@ -230,7 +259,7 @@ class SORLImageMixin(models.Model): else: return None - def get_cropped_image(self, geometry: str, quality: int, cropbox:str) -> dict: + def get_cropped_image(self, geometry: str, quality: int, cropbox: str) -> dict: cropped_image = get_thumbnail(self.image, geometry_string=geometry, # crop=crop, From d9ff3227dc35d11649856dfa8220e886f81da523 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 28 Jan 2020 18:54:27 +0300 Subject: [PATCH 070/101] address read only --- apps/establishment/serializers/back.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 8d02f252..6f4c8129 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -1,4 +1,5 @@ from functools import lru_cache +from pprint import pprint from django.db.models import F from django.utils.translation import gettext_lazy as _ @@ -49,12 +50,14 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria queryset=models.Address.objects.all(), write_only=True ) - socials = model_serializers.SocialNetworkRelatedSerializers(read_only=True, - many=True, ) - type = model_serializers.EstablishmentTypeBaseSerializer(source='establishment_type', - read_only=True) - address_id = serializers.PrimaryKeyRelatedField(write_only=True, source='address', - queryset=Address.objects.all()) + socials = model_serializers.SocialNetworkRelatedSerializers( + read_only=True, + many=True, + ) + type = model_serializers.EstablishmentTypeBaseSerializer( + source='establishment_type', + read_only=True, + ) tz = TimeZoneChoiceField() phones = serializers.ListField( source='contact_phones', @@ -132,7 +135,7 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): source='establishment_type', queryset=models.EstablishmentType.objects.all(), write_only=True ) - address = AddressDetailSerializer() + address = AddressDetailSerializer(read_only=True) emails = serializers.ListField( source='contact_emails', allow_null=True, From 8b014a79231526bc4280a8e443011f48c835a4af Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 19:24:20 +0300 Subject: [PATCH 071/101] finally fix issue w/ news patch --- apps/news/serializers.py | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index a6b2d72d..7ff7d285 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -155,6 +155,9 @@ class NewsDetailSerializer(NewsBaseSerializer): 'gallery', ) + def update(self, instance, validated_data): + return super().update(instance, validated_data) + class NewsDetailWebSerializer(NewsDetailSerializer): """News detail serializer for web users..""" @@ -260,7 +263,7 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer): instance = models.News.objects.get(pk=self.context['request'].data['id']) for key in ['slugs', 'title', 'locale_to_description_is_active', 'description']: for locale in locales: - if not attrs[key].get(locale): + if locale not in attrs[key]: attrs[key][locale] = getattr(instance, key).get(locale) return attrs @@ -381,27 +384,10 @@ class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer, def validate(self, attrs): """Overridden validate method.""" - if 'descriptions' in attrs: - descriptions = attrs.pop('descriptions') - locales = list(map(lambda x: x['locale'], descriptions)) - status_to_bool = { - 'active': True, - 'inactive': False, - } - attrs['slugs'] = {obj['locale']: obj['slug'] for obj in descriptions if 'slug' in obj} - attrs['title'] = {obj['locale']: obj['title'] for obj in descriptions if 'title' in obj} - attrs['locale_to_description_is_active'] = { - obj['locale']: status_to_bool[obj['status']] for obj in descriptions - } - attrs['description'] = {obj['locale']: obj['text'] for obj in descriptions if 'text' in obj} - if self.context['request'].method == 'PATCH': - instance = models.News.objects.get(pk=self.context['request'].data['id']) - for key in ['slugs', 'title', 'locale_to_description_is_active', 'description']: - for locale in locales: - if not attrs[key].get(locale): - attrs[key][locale] = getattr(instance, key).get(locale) + return super().validate(attrs) - return attrs + def update(self, instance, validated_data): + return super().update(instance, validated_data) class NewsBackOfficeGallerySerializer(serializers.ModelSerializer): From 577098e6cae6e42d0ce3d7efcbe97c17b528dbb2 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 20:58:54 +0300 Subject: [PATCH 072/101] partners changed relation --- .../migrations/0004_auto_20200128_1746.py | 44 ++++++++++++++++++ .../migrations/0005_auto_20200128_1754.py | 45 +++++++++++++++++++ apps/partner/models.py | 20 +++++---- 3 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 apps/partner/migrations/0004_auto_20200128_1746.py create mode 100644 apps/partner/migrations/0005_auto_20200128_1754.py diff --git a/apps/partner/migrations/0004_auto_20200128_1746.py b/apps/partner/migrations/0004_auto_20200128_1746.py new file mode 100644 index 00000000..27ebcec4 --- /dev/null +++ b/apps/partner/migrations/0004_auto_20200128_1746.py @@ -0,0 +1,44 @@ +# Generated by Django 2.2.7 on 2020-01-28 17:46 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +def make_relations(apps, schemaeditor): + PartnerToEstablishment = apps.get_model('partner', 'PartnerToEstablishment') + Partner = apps.get_model('partner', 'Partner') + Establishment = apps.get_model('establishment', 'Establishment') + touched_partners_ids = [] + for establishment in Establishment.objects.filter(partners__isnull=False): + for related_partner in establishment.partners.all(): + real_partner = Partner.objects.filter(name=related_partner.name, type=related_partner.type, + url=related_partner.url).first() + touched_partners_ids.append(related_partner.pk) + PartnerToEstablishment(establishment=establishment, partner=real_partner, partner_bind_date=real_partner.created).save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0083_establishment_instagram'), + ('partner', '0003_auto_20191121_1059'), + ] + + operations = [ + migrations.CreateModel( + name='PartnerToEstablishment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('partner_bind_date', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date partner binded')), + ('establishment', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='establishment.Establishment')), + ('partner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='partner.Partner')), + ], + ), + migrations.AddField( + model_name='partner', + name='establishments', + field=models.ManyToManyField(null=True, related_name='new_partners', through='partner.PartnerToEstablishment', to='establishment.Establishment', verbose_name='Establishments'), + ), + migrations.RunPython(make_relations, migrations.RunPython.noop), + ] diff --git a/apps/partner/migrations/0005_auto_20200128_1754.py b/apps/partner/migrations/0005_auto_20200128_1754.py new file mode 100644 index 00000000..82b3d912 --- /dev/null +++ b/apps/partner/migrations/0005_auto_20200128_1754.py @@ -0,0 +1,45 @@ +# Generated by Django 2.2.7 on 2020-01-28 17:54 + +from django.db import migrations, models +import django.db.models.deletion + + +def delete_unused_partners(apps, schema_editor): + PartnerToEstablishment = apps.get_model('partner', 'PartnerToEstablishment') + Partner = apps.get_model('partner', 'Partner') + ids_to_preserve = [] + for p_t_e in PartnerToEstablishment.objects.all(): + ids_to_preserve.append(PartnerToEstablishment.partner.pk) + PartnerToEstablishment.objects.exclude(id__in=ids_to_preserve).delete() + + +class Migration(migrations.Migration): + dependencies = [ + ('location', '0037_address_district_name'), + ('establishment', '0083_establishment_instagram'), + ('partner', '0004_auto_20200128_1746'), + ] + + operations = [ + migrations.RemoveField( + model_name='partner', + name='establishments', + ), + migrations.AddField( + model_name='partner', + name='country', + field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, + to='location.Country'), + ), + migrations.RemoveField( + model_name='partner', + name='establishment', + ), + migrations.AddField( + model_name='partner', + name='establishment', + field=models.ManyToManyField(related_name='partners', through='partner.PartnerToEstablishment', + to='establishment.Establishment', verbose_name='Establishments'), + ), + migrations.RunPython(delete_unused_partners, migrations.RunPython.noop, atomic=True) + ] diff --git a/apps/partner/models.py b/apps/partner/models.py index 5c5766c8..dec6df48 100644 --- a/apps/partner/models.py +++ b/apps/partner/models.py @@ -1,5 +1,6 @@ from django.db import models from django.utils.translation import gettext_lazy as _ +from django.utils import timezone from establishment.models import Establishment from utils.models import ImageMixin, ProjectBaseMixin @@ -19,18 +20,14 @@ class Partner(ProjectBaseMixin): name = models.CharField(_('name'), max_length=255, blank=True, null=True) url = models.URLField(verbose_name=_('Partner URL')) image = models.URLField(verbose_name=_('Partner image URL'), null=True) - establishment = models.ForeignKey( - Establishment, - verbose_name=_('Establishment'), - related_name='partners', - on_delete=models.CASCADE, - blank=True, - null=True, - ) + establishment = models.ManyToManyField('establishment.Establishment', related_name='partners', + through='PartnerToEstablishment', + verbose_name=_('Establishments')) type = models.PositiveSmallIntegerField(choices=MODEL_TYPES, default=PARTNER) starting_date = models.DateField(_('starting date'), blank=True, null=True) expiry_date = models.DateField(_('expiry date'), blank=True, null=True) price_per_month = models.DecimalField(_('price per month'), max_digits=10, decimal_places=2, blank=True, null=True) + country = models.ForeignKey('location.Country', null=True, default=None, on_delete=models.SET_NULL) class Meta: verbose_name = _('partner') @@ -38,3 +35,10 @@ class Partner(ProjectBaseMixin): def __str__(self): return f'{self.url}' + + +class PartnerToEstablishment(models.Model): + partner_bind_date = models.DateTimeField(default=timezone.now, editable=False, + verbose_name=_('Date partner binded')) + partner = models.ForeignKey(Partner, on_delete=models.CASCADE, null=True) + establishment = models.ForeignKey('establishment.Establishment', on_delete=models.CASCADE, null=True) From d2e28f519aa10ebcfac803a27aceae87fb88c144 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 21:00:02 +0300 Subject: [PATCH 073/101] fix migration --- apps/partner/migrations/0005_auto_20200128_1754.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/partner/migrations/0005_auto_20200128_1754.py b/apps/partner/migrations/0005_auto_20200128_1754.py index 82b3d912..2a92b134 100644 --- a/apps/partner/migrations/0005_auto_20200128_1754.py +++ b/apps/partner/migrations/0005_auto_20200128_1754.py @@ -9,7 +9,7 @@ def delete_unused_partners(apps, schema_editor): Partner = apps.get_model('partner', 'Partner') ids_to_preserve = [] for p_t_e in PartnerToEstablishment.objects.all(): - ids_to_preserve.append(PartnerToEstablishment.partner.pk) + ids_to_preserve.append(p_t_e.partner.pk) PartnerToEstablishment.objects.exclude(id__in=ids_to_preserve).delete() From 24f4abc76d86a6b9233715c0cb83800b03d2afdd Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 21:18:25 +0300 Subject: [PATCH 074/101] fix transfer partners --- apps/partner/migrations/0005_auto_20200128_1754.py | 2 +- apps/transfer/serializers/partner.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/partner/migrations/0005_auto_20200128_1754.py b/apps/partner/migrations/0005_auto_20200128_1754.py index 2a92b134..b26695c2 100644 --- a/apps/partner/migrations/0005_auto_20200128_1754.py +++ b/apps/partner/migrations/0005_auto_20200128_1754.py @@ -10,7 +10,7 @@ def delete_unused_partners(apps, schema_editor): ids_to_preserve = [] for p_t_e in PartnerToEstablishment.objects.all(): ids_to_preserve.append(p_t_e.partner.pk) - PartnerToEstablishment.objects.exclude(id__in=ids_to_preserve).delete() + Partner.objects.exclude(id__in=ids_to_preserve).delete() class Migration(migrations.Migration): diff --git a/apps/transfer/serializers/partner.py b/apps/transfer/serializers/partner.py index 61f56dea..1a41a5cc 100644 --- a/apps/transfer/serializers/partner.py +++ b/apps/transfer/serializers/partner.py @@ -43,10 +43,13 @@ class PartnerSerializer(serializers.Serializer): return establishment def create(self, validated_data): + establishment = validated_data.pop('establishment') obj, _ = Partner.objects.update_or_create( old_id=validated_data['old_id'], defaults=validated_data, ) + obj.establishment.set([establishment]) + obj.save() return obj From 8806bc4e33b9efa37431ca08f23c76863c635016 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 21:27:45 +0300 Subject: [PATCH 075/101] fix transfer script --- apps/partner/transfer_data.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/partner/transfer_data.py b/apps/partner/transfer_data.py index acda6c2c..de5dd43c 100644 --- a/apps/partner/transfer_data.py +++ b/apps/partner/transfer_data.py @@ -1,7 +1,7 @@ from pprint import pprint from establishment.models import Establishment -from partner.models import Partner +from partner.models import Partner, PartnerToEstablishment from transfer.models import EstablishmentBacklinks from transfer.serializers.partner import PartnerSerializer @@ -33,6 +33,20 @@ def transfer_partner(): else: pprint(f"Partner serializer errors: {serialized_data.errors}") + # here we manually delete duplicates + partners_to_remove_ids = [] + for partner_establishment_proxy in PartnerToEstablishment.objects.all(): + related_partner = partner_establishment_proxy.partner + actual_partner = Partner.objects.filter(type=related_partner.type, + url=related_partner.url, + name=related_partner.name).first() # exists for sure + if related_partner.pk != actual_partner.pk: + partners_to_remove_ids.append(related_partner.pk) + partner_establishment_proxy.partner = actual_partner + partner_establishment_proxy.save() + + Partner.objects.filter(id__in=partners_to_remove_ids).delete() + data_types = { "partner": [transfer_partner] From f58ac2a1cc82ad11f60a264c2a4d0942bd140bff Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Tue, 28 Jan 2020 23:21:16 +0300 Subject: [PATCH 076/101] partners --- apps/partner/filters.py | 11 +++++++++++ apps/partner/models.py | 19 +++++++++++++++++++ apps/partner/serializers/back.py | 23 ++++++++++++++++++++--- apps/partner/urls/back.py | 4 ++++ apps/partner/views/back.py | 14 ++++++++++++-- 5 files changed, 66 insertions(+), 5 deletions(-) diff --git a/apps/partner/filters.py b/apps/partner/filters.py index e9b32f5f..1965fd03 100644 --- a/apps/partner/filters.py +++ b/apps/partner/filters.py @@ -2,6 +2,7 @@ from django_filters import rest_framework as filters from partner.models import Partner +from django.core.validators import EMPTY_VALUES class PartnerFilterSet(filters.FilterSet): @@ -13,6 +14,7 @@ class PartnerFilterSet(filters.FilterSet): choices=Partner.MODEL_TYPES, help_text=f'Allows to filter partner list by partner type. ' f'Enum: {dict(Partner.MODEL_TYPES)}') + ordering = filters.CharFilter(method='sort_partner') class Meta: """Meta class.""" @@ -20,4 +22,13 @@ class PartnerFilterSet(filters.FilterSet): fields = ( 'establishment', 'type', + 'ordering', ) + + @staticmethod + def sort_partner(queryset, name, value): + if value not in EMPTY_VALUES: + if 'date_bind' in value: + value = value.replace('date_bind', 'partnertoestablishment__partner_bind_date') + queryset = queryset.order_by(value) + return queryset \ No newline at end of file diff --git a/apps/partner/models.py b/apps/partner/models.py index dec6df48..5c9f8af2 100644 --- a/apps/partner/models.py +++ b/apps/partner/models.py @@ -6,6 +6,19 @@ from establishment.models import Establishment from utils.models import ImageMixin, ProjectBaseMixin +class PartnerQueryset(models.QuerySet): + + def with_base_related(self): + return self.prefetch_related('establishment__establishment_type', 'establishment__establishment_subtypes', + 'establishment__awards', 'establishment__schedule', 'establishment__phones', + 'establishment__gallery', 'establishment__menu_set', + 'establishment__menu_set__plates', 'establishment__menu_set__plates__currency', + 'establishment__currency', 'establishment__address__city', + 'establishment__address__city__region', + 'establishment__address__city__region__country', + 'establishment__address__city__country', 'country') + + class Partner(ProjectBaseMixin): """Partner model.""" @@ -29,6 +42,8 @@ class Partner(ProjectBaseMixin): price_per_month = models.DecimalField(_('price per month'), max_digits=10, decimal_places=2, blank=True, null=True) country = models.ForeignKey('location.Country', null=True, default=None, on_delete=models.SET_NULL) + objects = PartnerQueryset.as_manager() + class Meta: verbose_name = _('partner') verbose_name_plural = _('partners') @@ -36,6 +51,10 @@ class Partner(ProjectBaseMixin): def __str__(self): return f'{self.url}' + @property + def type_display(self): + return self.MODEL_TYPES[self.type][1] + class PartnerToEstablishment(models.Model): partner_bind_date = models.DateTimeField(default=timezone.now, editable=False, diff --git a/apps/partner/serializers/back.py b/apps/partner/serializers/back.py index e9e03fe0..ebbbd2ca 100644 --- a/apps/partner/serializers/back.py +++ b/apps/partner/serializers/back.py @@ -1,21 +1,38 @@ """Back account serializers""" from rest_framework import serializers from partner.models import Partner +from establishment.serializers import EstablishmentShortSerializer +from location.serializers import CountrySimpleSerializer +from location.models import Country class BackPartnerSerializer(serializers.ModelSerializer): + establishments = EstablishmentShortSerializer(many=True, read_only=True, source='establishment') + country = CountrySimpleSerializer(read_only=True) + type_display = serializers.CharField(read_only=True) + country_id = serializers.PrimaryKeyRelatedField( + queryset=Country.objects.all(), + required=False, + write_only=True, + source='country' + ) + class Meta: model = Partner fields = ( 'id', - 'old_id', 'name', 'url', 'image', - 'establishment', - 'establishment_id', 'type', + 'type_display', 'starting_date', 'expiry_date', 'price_per_month', + 'country', + 'country_id', + 'establishments', ) + extra_kwargs = { + 'type': {'write_only': True}, + } diff --git a/apps/partner/urls/back.py b/apps/partner/urls/back.py index 27de2731..82ab3a31 100644 --- a/apps/partner/urls/back.py +++ b/apps/partner/urls/back.py @@ -8,4 +8,8 @@ app_name = 'partner' urlpatterns = [ path('', views.PartnerLstView.as_view(), name='partner-list-create'), path('/', views.PartnerRUDView.as_view(), name='partner-rud'), + # path('bind///', views.BindPartnerToEstablishmentView.as_view(), + # name='bind-partner-to-establishment'), + # path('unbind///', views.BindPartnerToEstablishmentView.as_view(), + # name='unbind-partner-from-establishment'), ] diff --git a/apps/partner/views/back.py b/apps/partner/views/back.py index 7ea440f0..762d3ef4 100644 --- a/apps/partner/views/back.py +++ b/apps/partner/views/back.py @@ -10,16 +10,26 @@ class PartnerLstView(generics.ListCreateAPIView): """Partner list/create view. Allows to get partners for current country, or create a new one. """ - queryset = Partner.objects.all() + queryset = Partner.objects.with_base_related() serializer_class = serializers.BackPartnerSerializer pagination_class = None permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] + # permission_classes = (permissions.AllowAny, ) filter_class = filters.PartnerFilterSet class PartnerRUDView(generics.RetrieveUpdateDestroyAPIView): """Partner RUD view.""" - queryset = Partner.objects.all() + queryset = Partner.objects.with_base_related() serializer_class = serializers.BackPartnerSerializer permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] + # permission_classes = (permissions.AllowAny, ) lookup_field = 'id' + + +# class BindPartnerToEstablishmentView(generics.GenericAPIView): +# pass + + +# class UnbindPartnerFromEstablishmentView(generics.DestroyAPIView): +# pass From 6a6d623ef3da39265cb1a1380fbcf21050766bf6 Mon Sep 17 00:00:00 2001 From: "a.gorbunov" Date: Wed, 29 Jan 2020 09:03:45 +0000 Subject: [PATCH 077/101] update roles list --- apps/account/serializers/back.py | 10 ++++++++-- apps/account/serializers/common.py | 24 +++++++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/apps/account/serializers/back.py b/apps/account/serializers/back.py index 2baaf656..4fba1c6f 100644 --- a/apps/account/serializers/back.py +++ b/apps/account/serializers/back.py @@ -2,7 +2,7 @@ from rest_framework import serializers from account import models -from account.serializers import RoleBaseSerializer, UserSerializer, subscriptions_handler +from account.serializers import RoleBaseSerializer, UserSerializer, subscriptions_handler, roles_handler from main.models import SiteSettings @@ -19,7 +19,7 @@ class _SiteSettingsSerializer(serializers.ModelSerializer): class BackUserSerializer(UserSerializer): last_country = _SiteSettingsSerializer(read_only=True) - roles = RoleBaseSerializer(many=True, read_only=True) + roles = RoleBaseSerializer(many=True) class Meta(UserSerializer.Meta): fields = ( @@ -115,6 +115,7 @@ class BackDetailUserSerializer(BackUserSerializer): def create(self, validated_data): subscriptions_list = [] + if 'subscription_types' in validated_data: subscriptions_list = validated_data.pop('subscription_types') @@ -127,11 +128,16 @@ class BackDetailUserSerializer(BackUserSerializer): def update(self, instance, validated_data): subscriptions_list = [] + if 'subscription_types' in validated_data: subscriptions_list = validated_data.pop('subscription_types') + if 'roles' in validated_data: + instance = roles_handler(validated_data.pop('roles'), instance) + instance = super().update(instance, validated_data) subscriptions_handler(subscriptions_list, instance) + return instance diff --git a/apps/account/serializers/common.py b/apps/account/serializers/common.py index 197c3a84..790cbfdf 100644 --- a/apps/account/serializers/common.py +++ b/apps/account/serializers/common.py @@ -8,6 +8,7 @@ from rest_framework import serializers from rest_framework import validators as rest_validators from account import models, tasks +from account.models import User, Role from main.serializers.common import NavigationBarPermissionBaseSerializer from notification.models import Subscribe, Subscriber from utils import exceptions as utils_exceptions @@ -16,6 +17,24 @@ from utils.methods import generate_string_code from phonenumber_field.serializerfields import PhoneNumberField +def roles_handler(roles_list: set, user: User) -> User: + """ + Sync roles for user + :param roles_list: list of user roles + :param user: user + :return: bool + """ + if not roles_list: + user.roles.clear() + return user + + ids = list(map(lambda role: role["id"] if "id" in role else None, roles_list)) + roles = Role.objects \ + .filter(id__in=ids) + user.roles.set(roles) + return user + + def subscriptions_handler(subscriptions_list, user): """ create or update subscriptions for user @@ -27,7 +46,7 @@ def subscriptions_handler(subscriptions_list, user): 'user': user, 'email': user.email, 'ip_address': user.last_ip, - 'country_code': user.last_country.country.code if user.last_country else None, + 'country_code': user.last_country.country.code if user.last_country and user.last_country.country else None, 'locale': user.locale, 'update_code': generate_string_code(), } @@ -42,6 +61,7 @@ def subscriptions_handler(subscriptions_list, user): class RoleBaseSerializer(serializers.ModelSerializer): """Serializer for model Role.""" + id = serializers.IntegerField() role_display = serializers.CharField(source='get_role_display', read_only=True) navigation_bar_permission = NavigationBarPermissionBaseSerializer(read_only=True) country_code = serializers.CharField(source='country.code', read_only=True, allow_null=True) @@ -133,6 +153,7 @@ class UserSerializer(serializers.ModelSerializer): def update(self, instance, validated_data): """Override update method""" subscriptions_list = [] + if 'subscription_types' in validated_data: subscriptions_list = validated_data.pop('subscription_types') @@ -164,6 +185,7 @@ class UserSerializer(serializers.ModelSerializer): emails=[validated_data['email'], ]) subscriptions_handler(subscriptions_list, instance) + return instance From fb3e8e5d715948f0d6a73e95f461848fd3cd7481 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 12:28:31 +0300 Subject: [PATCH 078/101] hide remove news --- apps/news/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/news/views.py b/apps/news/views.py index d4479b3c..9503631d 100644 --- a/apps/news/views.py +++ b/apps/news/views.py @@ -154,7 +154,7 @@ class NewsBackOfficeLCView(NewsBackOfficeMixinView, def get_queryset(self): """Override get_queryset method.""" - qs = super().get_queryset().with_extended_related() + qs = super().get_queryset().with_extended_related().visible() if 'ordering' in self.request.query_params: self.request.GET._mutable = True if '-publication_datetime' in self.request.query_params['ordering']: From 63fa81385e74b34fc4cca681fc0f09da33caf6d4 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 14:41:34 +0300 Subject: [PATCH 079/101] western_name creation --- apps/establishment/serializers/back.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 6f4c8129..634d10b4 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -98,6 +98,7 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria 'tags', 'tz', 'address_id', + 'western_name', ] def create(self, validated_data): From bcc5f2da51529b84a6a359108481f31857cae7f7 Mon Sep 17 00:00:00 2001 From: dormantman Date: Wed, 29 Jan 2020 15:17:15 +0300 Subject: [PATCH 080/101] Added menus method --- .../migrations/0084_auto_20200129_1113.py | 69 ++++++++++++++++ .../migrations/0085_menu_price.py | 18 +++++ apps/establishment/models.py | 7 +- apps/establishment/serializers/common.py | 80 +++++++++++-------- apps/establishment/urls/back.py | 2 + apps/establishment/views/back.py | 17 +++- 6 files changed, 155 insertions(+), 38 deletions(-) create mode 100644 apps/establishment/migrations/0084_auto_20200129_1113.py create mode 100644 apps/establishment/migrations/0085_menu_price.py diff --git a/apps/establishment/migrations/0084_auto_20200129_1113.py b/apps/establishment/migrations/0084_auto_20200129_1113.py new file mode 100644 index 00000000..c041c7bd --- /dev/null +++ b/apps/establishment/migrations/0084_auto_20200129_1113.py @@ -0,0 +1,69 @@ +# Generated by Django 2.2.7 on 2020-01-29 11:13 + +from django.conf import settings +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import utils.methods + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('establishment', '0083_establishment_instagram'), + ] + + operations = [ + migrations.CreateModel( + name='MenuFiles', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('file', models.FileField(blank=True, default=None, null=True, upload_to=utils.methods.file_path, validators=[django.core.validators.FileExtensionValidator(allowed_extensions=('jpg', 'jpeg', 'png', 'doc', 'docx', 'pdf'))], verbose_name='File')), + ('name', models.CharField(default='', max_length=255, verbose_name='name')), + ('type', models.CharField(default='', max_length=65, verbose_name='type')), + ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='menufiles_records_created', to=settings.AUTH_USER_MODEL, verbose_name='created by')), + ('modified_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='menufiles_records_modified', to=settings.AUTH_USER_MODEL, verbose_name='modified by')), + ], + options={ + 'verbose_name': 'menu upload', + 'verbose_name_plural': 'menu uploads', + }, + ), + migrations.RemoveField( + model_name='menuuploads', + name='created_by', + ), + migrations.RemoveField( + model_name='menuuploads', + name='menu', + ), + migrations.RemoveField( + model_name='menuuploads', + name='modified_by', + ), + migrations.AddField( + model_name='menu', + name='name', + field=models.CharField(default='', max_length=255, verbose_name='name'), + ), + migrations.AlterField( + model_name='menu', + name='schedule', + field=models.ManyToManyField(blank=True, to='timetable.Timetable', verbose_name='Menu schedule'), + ), + migrations.DeleteModel( + name='MenuGallery', + ), + migrations.DeleteModel( + name='MenuUploads', + ), + migrations.AddField( + model_name='menu', + name='uploads', + field=models.ManyToManyField(blank=True, to='establishment.MenuFiles', verbose_name='Menu files'), + ), + ] diff --git a/apps/establishment/migrations/0085_menu_price.py b/apps/establishment/migrations/0085_menu_price.py new file mode 100644 index 00000000..23afcba4 --- /dev/null +++ b/apps/establishment/migrations/0085_menu_price.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.7 on 2020-01-29 11:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0084_auto_20200129_1113'), + ] + + operations = [ + migrations.AddField( + model_name='menu', + name='price', + field=models.IntegerField(blank=True, default=None, null=True, verbose_name='price'), + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 83a7c5e8..9f5fa7fd 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -1283,6 +1283,7 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes): 'establishment.Establishment', verbose_name=_('establishment'), on_delete=models.CASCADE) is_drinks_included = models.BooleanField(_('is drinks included'), default=False) + price = models.IntegerField(blank=True, null=True, default=None, verbose_name=_('price')) schedule = models.ManyToManyField( to='timetable.Timetable', blank=True, @@ -1306,9 +1307,13 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes): class MenuFiles(FileMixin, BaseAttributes): """Menu files""" + TYPES = ( + ('image', 'Image'), + ('file', 'File') + ) name = models.CharField(_('name'), max_length=255, default='') - type = models.CharField(_('type'), max_length=65, default='') + type = models.CharField(_('type'), choices=TYPES, max_length=65, default='') class Meta: verbose_name = _('menu upload') diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 4bb1a8d4..f861d593 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -2,6 +2,7 @@ import logging from django.conf import settings +from django.shortcuts import get_object_or_404 from django.utils.translation import ugettext_lazy as _ from phonenumber_field.phonenumber import to_python as str_to_phonenumber from rest_framework import serializers @@ -9,24 +10,18 @@ from rest_framework import serializers from comment import models as comment_models from comment.serializers import common as comment_serializers from establishment import models -from establishment.models import Establishment from location.serializers import ( - AddressBaseSerializer, CityBaseSerializer, AddressDetailSerializer, - CityShortSerializer, -) -from location.serializers import ( - EstablishmentWineRegionBaseSerializer, - EstablishmentWineOriginBaseSerializer, + AddressBaseSerializer, AddressDetailSerializer, CityBaseSerializer, + CityShortSerializer, EstablishmentWineOriginBaseSerializer, EstablishmentWineRegionBaseSerializer, ) from main.serializers import AwardSerializer, CurrencySerializer from review.serializers import ReviewShortSerializer from tag.serializers import TagBaseSerializer from timetable.serialziers import ScheduleRUDSerializer from utils import exceptions as utils_exceptions -from utils.serializers import ImageBaseSerializer, CarouselCreateSerializer from utils.serializers import ( + CarouselCreateSerializer, FavoritesCreateSerializer, ImageBaseSerializer, ProjectModelSerializer, TranslatedField, - FavoritesCreateSerializer, ) logger = logging.getLogger(__name__) @@ -77,22 +72,41 @@ class PlateSerializer(ProjectModelSerializer): ] +class MenuFilesSerializers(ProjectModelSerializer): + menu_id = serializers.IntegerField(write_only=True) + + class Meta: + model = models.MenuFiles + fields = [ + 'id', + 'name', + 'type', + 'file', + 'menu_id' + ] + + def create(self, validated_data): + menu_id = validated_data.pop('menu_id') + menu = get_object_or_404(models.Menu, pk=menu_id) + instance = models.MenuFiles.objects.create(**validated_data) + menu.uploads.add(instance) + return instance + + class MenuSerializers(ProjectModelSerializer): name = serializers.CharField() establishment_id = serializers.PrimaryKeyRelatedField(queryset=models.Establishment.objects.all()) establishment_slug = serializers.CharField(read_only=True, source='establishment.slug') - price = serializers.IntegerField(read_only=True, source='establishment.price_level', required=False) - drinks_included = serializers.BooleanField(source='is_drinks_included', required=FavoritesCreateSerializer) + price = serializers.IntegerField(required=False) + drinks_included = serializers.BooleanField(source='is_drinks_included', required=False) schedules = ScheduleRUDSerializer(many=True, allow_null=True, required=False) - uploads = serializers.FileField(allow_null=True, required=False) - category_translated = serializers.CharField(read_only=True) + uploads = MenuFilesSerializers(many=True, read_only=True) class Meta: model = models.Menu fields = [ 'id', 'name', - 'establishment', 'establishment_id', 'establishment_slug', 'price', @@ -100,39 +114,35 @@ class MenuSerializers(ProjectModelSerializer): 'schedules', 'uploads', 'category', - 'category_translated', ] def create(self, validated_data): - print(validated_data, '\n\n\n\n\n') - establishment = models.Establishment.objects.get(pk=validated_data.pop('establishment')) - validated_data['establishment'] = establishment['id'] + validated_data['establishment'] = validated_data.pop('establishment_id') instance = models.Menu.objects.create(**validated_data) return instance -''' -{ - "name": "Menu test", - "establishment_id": 1, - "price": 1, - "drinks_included": true, - "schedules": [], - "uploads": null, - "category": null -} -''' - class MenuRUDSerializers(ProjectModelSerializer): - plates = PlateSerializer(read_only=True, many=True, source='plate_set') + name = serializers.CharField() + establishment_id = serializers.PrimaryKeyRelatedField(read_only=True) + establishment_slug = serializers.CharField(read_only=True, source='establishment.slug') + price = serializers.IntegerField(required=False) + drinks_included = serializers.BooleanField(source='is_drinks_included', required=False) + schedules = ScheduleRUDSerializer(many=True, allow_null=True, required=False) + uploads = MenuFilesSerializers(many=True) class Meta: model = models.Menu fields = [ 'id', + 'name', + 'establishment_id', + 'establishment_slug', + 'price', + 'drinks_included', + 'schedules', + 'uploads', 'category', - 'plates', - 'establishment' ] @@ -566,7 +576,7 @@ class EstablishmentCommentBaseSerializer(comment_serializers.CommentBaseSerializ 'created', 'text', 'mark', - 'nickname', + # 'nickname', 'profile_pic', 'status', 'status_display', @@ -606,7 +616,7 @@ class EstablishmentCommentRUDSerializer(comment_serializers.CommentBaseSerialize 'created', 'text', 'mark', - 'nickname', + # 'nickname', 'profile_pic', ] diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index 6db9d07a..b046cf85 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -37,6 +37,8 @@ urlpatterns = [ # name='menu-dishes-gallery-create-destroy'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus//', views.MenuRUDView.as_view(), name='menu-rud'), + path('menus/uploads/', views.MenuFilesListCreateView.as_view(), name='menu-files-list'), + path('menus/uploads//', views.MenuFilesRUDView.as_view(), name='menu-files-rud'), path('plates/', views.PlateListCreateView.as_view(), name='plates'), path('plates//', views.PlateRUDView.as_view(), name='plate-rud'), path('social_choice/', views.SocialChoiceListCreateView.as_view(), name='socials_choice'), diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index b56ebf10..e7e2ad44 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -2,7 +2,7 @@ from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend -from rest_framework import generics, permissions, response +from rest_framework import generics, permissions from rest_framework.response import Response from account.models import User @@ -136,6 +136,20 @@ class MenuRUDView(generics.RetrieveUpdateDestroyAPIView): permission_classes = [IsWineryReviewer | IsEstablishmentManager] +class MenuFilesListCreateView(generics.ListCreateAPIView): + """Menu files list create view.""" + serializer_class = serializers.MenuFilesSerializers + queryset = models.MenuFiles.objects.all() + permission_classes = [IsWineryReviewer | IsEstablishmentManager] + + +class MenuFilesRUDView(generics.RetrieveDestroyAPIView): + """Menu files RUD view.""" + serializer_class = serializers.MenuFilesSerializers + queryset = models.MenuFiles.objects.all() + permission_classes = [IsWineryReviewer | IsEstablishmentManager] + + class SocialChoiceListCreateView(generics.ListCreateAPIView): """SocialChoice list create view.""" serializer_class = serializers.SocialChoiceSerializers @@ -466,7 +480,6 @@ class MenuDishesRUDView(generics.RetrieveUpdateDestroyAPIView): queryset = models.Menu.objects.dishes().distinct() permission_classes = [IsWineryReviewer | IsEstablishmentManager] - # class MenuGalleryListView(generics.ListAPIView): # """Resource for returning gallery for menu for back-office users.""" # serializer_class = serializers.ImageBaseSerializer From 28d4a5ae4285bb0d0660462beb06a5e8d17926ab Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 15:21:51 +0300 Subject: [PATCH 081/101] reorganize partner models --- .../migrations/0006_auto_20200129_1201.py | 37 +++++++++++++++++++ apps/partner/models.py | 10 +++-- apps/partner/serializers/back.py | 2 +- apps/partner/serializers/common.py | 2 +- 4 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 apps/partner/migrations/0006_auto_20200129_1201.py diff --git a/apps/partner/migrations/0006_auto_20200129_1201.py b/apps/partner/migrations/0006_auto_20200129_1201.py new file mode 100644 index 00000000..0bb7487c --- /dev/null +++ b/apps/partner/migrations/0006_auto_20200129_1201.py @@ -0,0 +1,37 @@ +# Generated by Django 2.2.7 on 2020-01-29 12:01 + +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('partner', '0005_auto_20200128_1754'), + ] + + operations = [ + migrations.RemoveField( + model_name='partner', + name='image', + ), + migrations.RemoveField( + model_name='partner', + name='url', + ), + migrations.AddField( + model_name='partner', + name='images', + field=django.contrib.postgres.fields.ArrayField(base_field=models.URLField(verbose_name='Partner image URL'), blank=True, default=None, null=True, size=None), + ), + migrations.AddField( + model_name='partnertoestablishment', + name='image', + field=models.URLField(null=True, verbose_name='Partner image URL'), + ), + migrations.AddField( + model_name='partnertoestablishment', + name='url', + field=models.URLField(blank=True, default=None, null=True, verbose_name='Establishment to Partner URL'), + ), + ] diff --git a/apps/partner/models.py b/apps/partner/models.py index 5c9f8af2..e50fd939 100644 --- a/apps/partner/models.py +++ b/apps/partner/models.py @@ -1,6 +1,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ from django.utils import timezone +from django.contrib.postgres.fields import ArrayField from establishment.models import Establishment from utils.models import ImageMixin, ProjectBaseMixin @@ -31,8 +32,9 @@ class Partner(ProjectBaseMixin): old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None) name = models.CharField(_('name'), max_length=255, blank=True, null=True) - url = models.URLField(verbose_name=_('Partner URL')) - image = models.URLField(verbose_name=_('Partner image URL'), null=True) + images = ArrayField( + models.URLField(verbose_name=_('Partner image URL')), blank=True, null=True, default=None, + ) establishment = models.ManyToManyField('establishment.Establishment', related_name='partners', through='PartnerToEstablishment', verbose_name=_('Establishments')) @@ -49,7 +51,7 @@ class Partner(ProjectBaseMixin): verbose_name_plural = _('partners') def __str__(self): - return f'{self.url}' + return f'{self.name}' @property def type_display(self): @@ -59,5 +61,7 @@ class Partner(ProjectBaseMixin): class PartnerToEstablishment(models.Model): partner_bind_date = models.DateTimeField(default=timezone.now, editable=False, verbose_name=_('Date partner binded')) + url = models.URLField(verbose_name=_('Establishment to Partner URL'), null=True, blank=True, default=None) + image = models.URLField(verbose_name=_('Partner image URL'), null=True) partner = models.ForeignKey(Partner, on_delete=models.CASCADE, null=True) establishment = models.ForeignKey('establishment.Establishment', on_delete=models.CASCADE, null=True) diff --git a/apps/partner/serializers/back.py b/apps/partner/serializers/back.py index ebbbd2ca..ba676bfa 100644 --- a/apps/partner/serializers/back.py +++ b/apps/partner/serializers/back.py @@ -23,7 +23,7 @@ class BackPartnerSerializer(serializers.ModelSerializer): 'id', 'name', 'url', - 'image', + # 'image', 'type', 'type_display', 'starting_date', diff --git a/apps/partner/serializers/common.py b/apps/partner/serializers/common.py index 1d5a6b23..83053f26 100644 --- a/apps/partner/serializers/common.py +++ b/apps/partner/serializers/common.py @@ -11,6 +11,6 @@ class PartnerSerializer(serializers.ModelSerializer): model = models.Partner fields = ( 'id', - 'image', + # 'image', 'url' ) From a6db15ed50c2132c8b4ffc21422b7ea81026e537 Mon Sep 17 00:00:00 2001 From: dormantman Date: Wed, 29 Jan 2020 16:11:53 +0300 Subject: [PATCH 082/101] Added menu dishes --- apps/establishment/models.py | 64 +++++++++------ apps/establishment/serializers/back.py | 99 ++++-------------------- apps/establishment/serializers/common.py | 15 +++- apps/establishment/urls/back.py | 6 +- apps/establishment/views/back.py | 58 +------------- 5 files changed, 74 insertions(+), 168 deletions(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 9f5fa7fd..22cd9925 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -6,36 +6,32 @@ from typing import List import elasticsearch_dsl from django.conf import settings -from django.shortcuts import get_object_or_404 from django.contrib.contenttypes import fields as generic from django.contrib.gis.db.models.functions import Distance from django.contrib.gis.geos import Point from django.contrib.gis.measure import Distance as DistanceMeasure from django.contrib.postgres.fields import ArrayField -from django.contrib.postgres.search import TrigramDistance, TrigramSimilarity from django.contrib.postgres.indexes import GinIndex +from django.contrib.postgres.search import TrigramSimilarity from django.core.exceptions import ValidationError -from django.core.validators import MinValueValidator, MaxValueValidator, FileExtensionValidator +from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models -from django.db.models import When, Case, F, ExpressionWrapper, Subquery, Q, Prefetch, Sum +from django.db.models import Case, ExpressionWrapper, F, Prefetch, Q, Subquery, When +from django.shortcuts import get_object_or_404 from django.utils import timezone from django.utils.translation import gettext_lazy as _ from phonenumber_field.modelfields import PhoneNumberField from timezone_field import TimeZoneField from location.models import Address -from timetable.models import Timetable -from location.models import WineOriginAddressMixin from main.models import Award, Currency from review.models import Review from tag.models import Tag +from timetable.models import Timetable from utils.methods import transform_into_readable_str from utils.models import ( - ProjectBaseMixin, TJSONField, URLImageMixin, - TranslatedFieldsMixin, BaseAttributes, GalleryMixin, - IntermediateGalleryModelMixin, HasTagsMixin, - FavoritesMixin, TypeDefaultImageMixin, FileMixin, - ImageMixin, + BaseAttributes, FavoritesMixin, FileMixin, GalleryMixin, HasTagsMixin, IntermediateGalleryModelMixin, + ProjectBaseMixin, TJSONField, TranslatedFieldsMixin, TypeDefaultImageMixin, URLImageMixin, ) @@ -564,8 +560,8 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, verbose_name=_('Facebook URL')) twitter = models.URLField(blank=True, null=True, default=None, max_length=255, verbose_name=_('Twitter URL')) - instagram =models.URLField(blank=True, null=True, default=None, max_length=255, - verbose_name=_('Instagram URL')) + instagram = models.URLField(blank=True, null=True, default=None, max_length=255, + verbose_name=_('Instagram URL')) lafourchette = models.URLField(blank=True, null=True, default=None, max_length=255, verbose_name=_('Lafourchette URL')) guestonline_id = models.PositiveIntegerField(blank=True, verbose_name=_('guestonline id'), @@ -737,7 +733,8 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, now_at_est_tz = datetime.now(tz=self.tz) current_week = now_at_est_tz.weekday() schedule_for_today = self.schedule.filter(weekday=current_week).first() - if schedule_for_today is None or schedule_for_today.opening_time is None or schedule_for_today.ending_time is None: + if schedule_for_today is None or schedule_for_today.opening_time is None or schedule_for_today.ending_time is\ + None: return False time_at_est_tz = now_at_est_tz.time() return schedule_for_today.ending_time > time_at_est_tz > schedule_for_today.opening_time @@ -749,8 +746,10 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, @property def tags_indexing(self): - return [{'id': tag.metadata.id, - 'label': tag.metadata.label} for tag in self.tags.all()] + return [{ + 'id': tag.metadata.id, + 'label': tag.metadata.label + } for tag in self.tags.all()] @property def last_published_review(self): @@ -1244,6 +1243,24 @@ class Plate(TranslatedFieldsMixin, models.Model): verbose_name_plural = _('plates') +class MenuDish(BaseAttributes): + """Dish model.""" + + STR_FIELD_NAME = 'category' + + name = models.CharField(_('name'), max_length=255, default='') + category = TJSONField( + blank=True, null=True, default=None, verbose_name=_('category'), + help_text='{"en-GB":"some text"}') + price = models.IntegerField(blank=True, null=True, default=None, verbose_name=_('price')) + signature = models.BooleanField(_('signature'), default=False) + + class Meta: + verbose_name = _('dish') + verbose_name_plural = _('dishes') + ordering = ('-created',) + + class MenuQuerySet(models.QuerySet): def with_schedule_plates_establishment(self): return self.select_related( @@ -1270,15 +1287,10 @@ class MenuQuerySet(models.QuerySet): return self.filter(category__icontains=value) -class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes): +class Menu(TranslatedFieldsMixin, BaseAttributes): """Menu model.""" - STR_FIELD_NAME = 'category' - name = models.CharField(_('name'), max_length=255, default='') - category = TJSONField( - blank=True, null=True, default=None, verbose_name=_('category'), - help_text='{"en-GB":"some text"}') establishment = models.ForeignKey( 'establishment.Establishment', verbose_name=_('establishment'), on_delete=models.CASCADE) @@ -1294,6 +1306,14 @@ class Menu(GalleryMixin, TranslatedFieldsMixin, BaseAttributes): blank=True, verbose_name=_('Menu files'), ) + dishes = models.ManyToManyField( + to='MenuDish', + blank=True, + verbose_name=_('Menu dishes') + ) + category = TJSONField( + blank=True, null=True, default=None, verbose_name=_('category'), + help_text='{"en-GB":"some text"}') old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index e3adb490..4b92d985 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -1,12 +1,14 @@ from functools import lru_cache from django.db.models import F +from django.shortcuts import get_object_or_404 from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from account.serializers.common import UserShortSerializer from establishment import models, serializers as model_serializers from establishment.models import ContactPhone, EstablishmentEmployee, ContactEmail +from establishment.serializers import MenuDishSerializer from gallery.models import Image from location.models import Address from location.serializers import AddressDetailSerializer, TranslatedField @@ -580,109 +582,36 @@ class EstablishmentEmployeePositionsSerializer(serializers.ModelSerializer): ] -class _PlateSerializer(ProjectModelSerializer): - name_translated = TranslatedField() - - class Meta: - model = models.Plate - fields = [ - 'name_translated', - 'price', - ] - - -class _MenuUploadsSerializer(serializers.Serializer): - id = serializers.IntegerField() - title = serializers.CharField() - original_url = serializers.URLField() - - class MenuDishesSerializer(ProjectModelSerializer): """for dessert, main_course and starter category""" - plates = _PlateSerializer(read_only=True, many=True, source='plate_set', allow_null=True) - category_translated = serializers.CharField(read_only=True) - last_update = serializers.DateTimeField(source='created') - gallery = ImageBaseSerializer(read_only=True, source='crop_gallery', many=True) + establishment_id = serializers.PrimaryKeyRelatedField(read_only=True) + establishment_slug = serializers.CharField(read_only=True, source='establishment.slug') + dishes = MenuDishSerializer(many=True, read_only=True) class Meta: model = models.Menu fields = [ 'id', - 'category', - 'category_translated', - 'establishment', - 'is_drinks_included', - 'schedule', - 'plates', - 'last_update', - 'gallery', + 'establishment_id', + 'establishment_slug', + 'dishes', ] class MenuDishesRUDSerializers(ProjectModelSerializer): """for dessert, main_course and starter category""" - plates = _PlateSerializer(read_only=True, many=True, source='plate_set', allow_null=True) - gallery = ImageBaseSerializer(read_only=True, source='crop_gallery', many=True) + establishment_id = serializers.PrimaryKeyRelatedField(queryset=models.Establishment.objects.all()) + establishment_slug = serializers.CharField(read_only=True, source='establishment.slug') + dishes = MenuDishSerializer(many=True, read_only=True) class Meta: model = models.Menu fields = [ 'id', - 'category', - 'plates', - 'establishment', - 'is_drinks_included', - 'schedule', - 'gallery', + 'establishment_id', + 'establishment_slug', + 'dishes', ] - -# class MenuGallerySerializer(serializers.ModelSerializer): -# """Serializer class for model MenuGallery.""" -# -# class Meta: -# """Meta class""" -# -# model = models.MenuGallery -# fields = [ -# 'id', -# 'is_main', -# ] -# -# @property -# def request_kwargs(self): -# """Get url kwargs from request.""" -# return self.context.get('request').parser_context.get('kwargs') -# -# def create(self, validated_data): -# menu_pk = self.request_kwargs.get('pk') -# image_id = self.request_kwargs.get('image_id') -# qs = models.MenuGallery.objects.filter(image_id=image_id, menu_id=menu_pk) -# instance = qs.first() -# if instance: -# qs.update(**validated_data) -# return instance -# return super().create(validated_data) -# -# def validate(self, attrs): -# """Override validate method.""" -# menu_pk = self.request_kwargs.get('pk') -# image_id = self.request_kwargs.get('image_id') -# -# menu_qs = models.Menu.objects.filter(pk=menu_pk) -# image_qs = Image.objects.filter(id=image_id) -# -# if not menu_qs.exists(): -# raise serializers.ValidationError({'detail': _('Menu not found')}) -# if not image_qs.exists(): -# raise serializers.ValidationError({'detail': _('Image not found')}) -# -# menu = menu_qs.first() -# image = image_qs.first() -# -# attrs['menu'] = menu -# attrs['image'] = image -# -# return attrs diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index f861d593..3c58f476 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -72,6 +72,19 @@ class PlateSerializer(ProjectModelSerializer): ] +class MenuDishSerializer(ProjectModelSerializer): + class Meta: + model = models.MenuDish + fields = [ + 'id', + 'name', + 'category', + 'category_translated', + 'price', + 'signature' + ] + + class MenuFilesSerializers(ProjectModelSerializer): menu_id = serializers.IntegerField(write_only=True) @@ -113,7 +126,6 @@ class MenuSerializers(ProjectModelSerializer): 'drinks_included', 'schedules', 'uploads', - 'category', ] def create(self, validated_data): @@ -142,7 +154,6 @@ class MenuRUDSerializers(ProjectModelSerializer): 'drinks_included', 'schedules', 'uploads', - 'category', ] diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index b046cf85..053d47fd 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -30,13 +30,11 @@ urlpatterns = [ name='note-rud'), path('slug//admin/', views.EstablishmentAdminView.as_view(), name='establishment-admin-list'), - path('menus/dishes/', views.MenuDishesListCreateView.as_view(), name='menu-dishes-list'), + path('menus/dishes/', views.MenuDishesListView.as_view(), name='menu-dishes-list'), path('menus/dishes//', views.MenuDishesRUDView.as_view(), name='menu-dishes-rud'), - # path('menus/dishes//gallery/', views.MenuGalleryListView.as_view(), name='menu-dishes-gallery-list'), - # path('menus/dishes//gallery//', views.MenuGalleryCreateDestroyView.as_view(), - # name='menu-dishes-gallery-create-destroy'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus//', views.MenuRUDView.as_view(), name='menu-rud'), + path('menus/slug//', views.MenuRUDView.as_view(), name='menu-rud'), path('menus/uploads/', views.MenuFilesListCreateView.as_view(), name='menu-files-list'), path('menus/uploads//', views.MenuFilesRUDView.as_view(), name='menu-files-rud'), path('plates/', views.PlateListCreateView.as_view(), name='plates'), diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index e7e2ad44..d1384b1e 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -466,10 +466,10 @@ class EstablishmentAdminView(generics.ListAPIView): return User.objects.establishment_admin(establishment).distinct() -class MenuDishesListCreateView(generics.ListCreateAPIView): +class MenuDishesListView(generics.ListAPIView): """Menu (dessert, main_course, starter) list create view.""" serializer_class = serializers.MenuDishesSerializer - queryset = models.Menu.objects.with_schedule_plates_establishment().dishes().distinct() + queryset = models.Menu.objects.all() permission_classes = [IsWineryReviewer | IsEstablishmentManager] filter_class = filters.MenuDishesBackFilter @@ -477,57 +477,5 @@ class MenuDishesListCreateView(generics.ListCreateAPIView): class MenuDishesRUDView(generics.RetrieveUpdateDestroyAPIView): """Menu (dessert, main_course, starter) RUD view.""" serializer_class = serializers.MenuDishesRUDSerializers - queryset = models.Menu.objects.dishes().distinct() + queryset = models.Menu.objects.all() permission_classes = [IsWineryReviewer | IsEstablishmentManager] - -# class MenuGalleryListView(generics.ListAPIView): -# """Resource for returning gallery for menu for back-office users.""" -# serializer_class = serializers.ImageBaseSerializer -# permission_classes = [IsWineryReviewer | IsEstablishmentManager] -# queryset = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() -# -# def get_object(self): -# """Override get_object method.""" -# qs = super(MenuGalleryListView, self).get_queryset() -# menu = get_object_or_404(qs, pk=self.kwargs.get('pk')) -# -# # May raise a permission denied -# # self.check_object_permissions(self.request, menu) -# -# return menu -# -# def get_queryset(self): -# """Override get_queryset method.""" -# return self.get_object().crop_gallery -# -# -# class MenuGalleryCreateDestroyView(CreateDestroyGalleryViewMixin): -# """Resource for a create gallery for menu for back-office users.""" -# serializer_class = serializers.MenuGallerySerializer -# permission_classes = [IsWineryReviewer | IsEstablishmentManager] -# -# def get_queryset(self): -# """Override get_queryset method.""" -# qs = models.Menu.objects.with_schedule_plates_establishment().with_gallery().dishes() -# return qs -# -# def create(self, request, *args, **kwargs): -# _ = super().create(request, *args, **kwargs) -# news_qs = self.filter_queryset(self.get_queryset()) -# return response.Response( -# data=serializers.MenuDishesRUDSerializers(get_object_or_404(news_qs, pk=kwargs.get('pk'))).data -# ) -# -# def get_object(self): -# """ -# Returns the object the view is displaying. -# """ -# menu_qs = self.filter_queryset(self.get_queryset()) -# -# menu = get_object_or_404(menu_qs, pk=self.kwargs.get('pk')) -# gallery = get_object_or_404(menu.menu_gallery, image_id=self.kwargs.get('image_id')) -# -# # May raise a permission denied -# self.check_object_permissions(self.request, gallery) -# -# return gallery From 4fde19d23e4fe143b34954f78ecb1df2a591bf7d Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 16:53:04 +0300 Subject: [PATCH 083/101] fix partner transfer --- apps/transfer/serializers/partner.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/transfer/serializers/partner.py b/apps/transfer/serializers/partner.py index 1a41a5cc..9d79e00c 100644 --- a/apps/transfer/serializers/partner.py +++ b/apps/transfer/serializers/partner.py @@ -1,7 +1,7 @@ from rest_framework import serializers from establishment.models import Establishment -from partner.models import Partner +from partner.models import Partner, PartnerToEstablishment class PartnerSerializer(serializers.Serializer): @@ -44,12 +44,23 @@ class PartnerSerializer(serializers.Serializer): def create(self, validated_data): establishment = validated_data.pop('establishment') - obj, _ = Partner.objects.update_or_create( + url = validated_data.pop('url') + image = validated_data.pop('image') + obj, is_created = Partner.objects.update_or_create( old_id=validated_data['old_id'], defaults=validated_data, ) obj.establishment.set([establishment]) + if obj.created: + obj.images = [image] + else: + obj.images.append(image) obj.save() + + p_t_e = PartnerToEstablishment.objects.filter(establishment=establishment, partner=obj).first() + p_t_e.url = url + p_t_e.image = image + p_t_e.save() return obj From 302e22045ee21ce1861ae2830dae495ddebe1af4 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Wed, 29 Jan 2020 16:59:10 +0300 Subject: [PATCH 084/101] fixes --- apps/establishment/urls/common.py | 2 +- apps/location/models.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/establishment/urls/common.py b/apps/establishment/urls/common.py index 25f2b14f..0bb13cf6 100644 --- a/apps/establishment/urls/common.py +++ b/apps/establishment/urls/common.py @@ -15,7 +15,7 @@ urlpatterns = [ name='create-comment'), path('slug//comments//', views.EstablishmentCommentRUDView.as_view(), name='rud-comment'), - path('slug//collections/', views.EstablishmentFavoritesCreateDestroyView.as_view(), + path('slug//favorites/', views.EstablishmentFavoritesCreateDestroyView.as_view(), name='create-destroy-favorites'), # similar establishments by type/subtype diff --git a/apps/location/models.py b/apps/location/models.py index a50b1f41..579addd1 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -178,12 +178,12 @@ class City(models.Model, TranslatedFieldsMixin): verbose_name = _('city') def __str__(self): - return self.name + return self.name_dumped @property def name_dumped(self): """Used for indexing as string""" - return dumps(self.name) + return f'{self.id}: {dumps(self.name)}' @property def image_object(self): From 45acfa37c9c5516c203aab581ca4af1b9abb6d3e Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 17:00:13 +0300 Subject: [PATCH 085/101] partners transfer --- apps/transfer/serializers/partner.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/transfer/serializers/partner.py b/apps/transfer/serializers/partner.py index 9d79e00c..e50ffe9f 100644 --- a/apps/transfer/serializers/partner.py +++ b/apps/transfer/serializers/partner.py @@ -46,11 +46,19 @@ class PartnerSerializer(serializers.Serializer): establishment = validated_data.pop('establishment') url = validated_data.pop('url') image = validated_data.pop('image') + + old_id = validated_data.pop('old_id') + created = validated_data.pop('created') + obj, is_created = Partner.objects.update_or_create( old_id=validated_data['old_id'], defaults=validated_data, ) - obj.establishment.set([establishment]) + + obj.old_id = old_id + obj.created = created + + obj.establishment.append([establishment]) if obj.created: obj.images = [image] else: From 869aa7b4f4ce28d092bbe2e6ccc90405047bf3e3 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 17:02:58 +0300 Subject: [PATCH 086/101] partners transfer --- apps/transfer/serializers/partner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/transfer/serializers/partner.py b/apps/transfer/serializers/partner.py index e50ffe9f..f3bfbfa4 100644 --- a/apps/transfer/serializers/partner.py +++ b/apps/transfer/serializers/partner.py @@ -51,8 +51,8 @@ class PartnerSerializer(serializers.Serializer): created = validated_data.pop('created') obj, is_created = Partner.objects.update_or_create( - old_id=validated_data['old_id'], - defaults=validated_data, + # old_id=validated_data['old_id'], + **validated_data ) obj.old_id = old_id From 917e50083834b2ba844775899c8591683bb3c627 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 17:07:06 +0300 Subject: [PATCH 087/101] partners transfer --- apps/transfer/serializers/partner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/transfer/serializers/partner.py b/apps/transfer/serializers/partner.py index f3bfbfa4..e65a5c72 100644 --- a/apps/transfer/serializers/partner.py +++ b/apps/transfer/serializers/partner.py @@ -58,7 +58,7 @@ class PartnerSerializer(serializers.Serializer): obj.old_id = old_id obj.created = created - obj.establishment.append([establishment]) + obj.establishment.add([establishment]) if obj.created: obj.images = [image] else: From 65b0b56c71b41ce1e0d559f0f835a80160560ef9 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 17:15:12 +0300 Subject: [PATCH 088/101] transfer partners --- apps/transfer/serializers/partner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/transfer/serializers/partner.py b/apps/transfer/serializers/partner.py index e65a5c72..7d2f80a6 100644 --- a/apps/transfer/serializers/partner.py +++ b/apps/transfer/serializers/partner.py @@ -59,7 +59,7 @@ class PartnerSerializer(serializers.Serializer): obj.created = created obj.establishment.add([establishment]) - if obj.created: + if is_created: obj.images = [image] else: obj.images.append(image) From 38d2e002b7969c1ccf850e13b83bb8a1e8e5028e Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 17:16:42 +0300 Subject: [PATCH 089/101] partners transfer --- apps/transfer/serializers/partner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/transfer/serializers/partner.py b/apps/transfer/serializers/partner.py index 7d2f80a6..f419ff1a 100644 --- a/apps/transfer/serializers/partner.py +++ b/apps/transfer/serializers/partner.py @@ -58,7 +58,7 @@ class PartnerSerializer(serializers.Serializer): obj.old_id = old_id obj.created = created - obj.establishment.add([establishment]) + obj.establishment.add(establishment) if is_created: obj.images = [image] else: From 6dd14ab80de311dd3b85acec7c4341a459688903 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 17:46:59 +0300 Subject: [PATCH 090/101] transfer partners --- apps/partner/transfer_data.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/apps/partner/transfer_data.py b/apps/partner/transfer_data.py index de5dd43c..0f111eba 100644 --- a/apps/partner/transfer_data.py +++ b/apps/partner/transfer_data.py @@ -33,20 +33,6 @@ def transfer_partner(): else: pprint(f"Partner serializer errors: {serialized_data.errors}") - # here we manually delete duplicates - partners_to_remove_ids = [] - for partner_establishment_proxy in PartnerToEstablishment.objects.all(): - related_partner = partner_establishment_proxy.partner - actual_partner = Partner.objects.filter(type=related_partner.type, - url=related_partner.url, - name=related_partner.name).first() # exists for sure - if related_partner.pk != actual_partner.pk: - partners_to_remove_ids.append(related_partner.pk) - partner_establishment_proxy.partner = actual_partner - partner_establishment_proxy.save() - - Partner.objects.filter(id__in=partners_to_remove_ids).delete() - data_types = { "partner": [transfer_partner] From 042d749d77683ca6bf2eb9f3aa1a6cac2a8c944a Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 17:53:25 +0300 Subject: [PATCH 091/101] added pictures route && removed partners pictures duplicates --- apps/partner/serializers/back.py | 9 +++++++++ apps/partner/urls/back.py | 1 + apps/partner/views/back.py | 7 +++++++ apps/transfer/serializers/partner.py | 2 +- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/partner/serializers/back.py b/apps/partner/serializers/back.py index ba676bfa..23c43787 100644 --- a/apps/partner/serializers/back.py +++ b/apps/partner/serializers/back.py @@ -36,3 +36,12 @@ class BackPartnerSerializer(serializers.ModelSerializer): extra_kwargs = { 'type': {'write_only': True}, } + + +class PartnerPicturesSerializer(serializers.ModelSerializer): + + class Meta: + model = Partner + fields = ( + 'images', + ) diff --git a/apps/partner/urls/back.py b/apps/partner/urls/back.py index 82ab3a31..cc6bed24 100644 --- a/apps/partner/urls/back.py +++ b/apps/partner/urls/back.py @@ -8,6 +8,7 @@ app_name = 'partner' urlpatterns = [ path('', views.PartnerLstView.as_view(), name='partner-list-create'), path('/', views.PartnerRUDView.as_view(), name='partner-rud'), + path('pictures//', views.PartnerPicturesListView.as_view(), name='partner-pictures-get'), # path('bind///', views.BindPartnerToEstablishmentView.as_view(), # name='bind-partner-to-establishment'), # path('unbind///', views.BindPartnerToEstablishmentView.as_view(), diff --git a/apps/partner/views/back.py b/apps/partner/views/back.py index 762d3ef4..4d51e76a 100644 --- a/apps/partner/views/back.py +++ b/apps/partner/views/back.py @@ -27,6 +27,13 @@ class PartnerRUDView(generics.RetrieveUpdateDestroyAPIView): lookup_field = 'id' +class PartnerPicturesListView(generics.RetrieveAPIView): + lookup_field = 'id' + serializer_class = serializers.PartnerPicturesSerializer + queryset = Partner.objects.with_base_related() + # permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] + permission_classes = (permissions.AllowAny, ) + # class BindPartnerToEstablishmentView(generics.GenericAPIView): # pass diff --git a/apps/transfer/serializers/partner.py b/apps/transfer/serializers/partner.py index f419ff1a..2bfc7183 100644 --- a/apps/transfer/serializers/partner.py +++ b/apps/transfer/serializers/partner.py @@ -61,7 +61,7 @@ class PartnerSerializer(serializers.Serializer): obj.establishment.add(establishment) if is_created: obj.images = [image] - else: + elif image not in obj.images: obj.images.append(image) obj.save() From 19cf1b07d651482c0e210f1cacb5bc19137e551b Mon Sep 17 00:00:00 2001 From: dormantman Date: Wed, 29 Jan 2020 18:19:28 +0300 Subject: [PATCH 092/101] Added rud finding --- apps/establishment/models.py | 11 ++++--- apps/establishment/serializers/back.py | 27 ++++++++++++++-- apps/establishment/serializers/common.py | 1 - apps/establishment/urls/back.py | 2 ++ apps/establishment/views/back.py | 39 ++++++++++++++++++++---- 5 files changed, 67 insertions(+), 13 deletions(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 22cd9925..9999d25a 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -733,7 +733,7 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, now_at_est_tz = datetime.now(tz=self.tz) current_week = now_at_est_tz.weekday() schedule_for_today = self.schedule.filter(weekday=current_week).first() - if schedule_for_today is None or schedule_for_today.opening_time is None or schedule_for_today.ending_time is\ + if schedule_for_today is None or schedule_for_today.opening_time is None or schedule_for_today.ending_time is \ None: return False time_at_est_tz = now_at_est_tz.time() @@ -747,9 +747,9 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, @property def tags_indexing(self): return [{ - 'id': tag.metadata.id, - 'label': tag.metadata.label - } for tag in self.tags.all()] + 'id': tag.metadata.id, + 'label': tag.metadata.label + } for tag in self.tags.all()] @property def last_published_review(self): @@ -1286,6 +1286,9 @@ class MenuQuerySet(models.QuerySet): """Search by category.""" return self.filter(category__icontains=value) + def with_dishes(self): + return self.filter(~Q(dishes=None)) + class Menu(TranslatedFieldsMixin, BaseAttributes): """Menu model.""" diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 4b92d985..85fe8fa2 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -7,7 +7,7 @@ from rest_framework import serializers from account.serializers.common import UserShortSerializer from establishment import models, serializers as model_serializers -from establishment.models import ContactPhone, EstablishmentEmployee, ContactEmail +from establishment.models import ContactEmail, ContactPhone, EstablishmentEmployee from establishment.serializers import MenuDishSerializer from gallery.models import Image from location.models import Address @@ -599,6 +599,30 @@ class MenuDishesSerializer(ProjectModelSerializer): ] +class MenuDishesCreateSerializer(ProjectModelSerializer): + """Menu dishes create serializer""" + + menu_id = serializers.IntegerField(write_only=True) + + class Meta: + model = models.MenuDish + fields = [ + 'id', + 'name', + 'category', + 'price', + 'signature', + 'menu_id' + ] + + def create(self, validated_data): + menu_id = validated_data.pop('menu_id') + menu = get_object_or_404(models.Menu, pk=menu_id) + instance = models.MenuDish.objects.create(**validated_data) + menu.dishes.add(instance) + return instance + + class MenuDishesRUDSerializers(ProjectModelSerializer): """for dessert, main_course and starter category""" @@ -614,4 +638,3 @@ class MenuDishesRUDSerializers(ProjectModelSerializer): 'establishment_slug', 'dishes', ] - diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 3c58f476..3af43e27 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -79,7 +79,6 @@ class MenuDishSerializer(ProjectModelSerializer): 'id', 'name', 'category', - 'category_translated', 'price', 'signature' ] diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index 053d47fd..09c2f2a8 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -31,7 +31,9 @@ urlpatterns = [ path('slug//admin/', views.EstablishmentAdminView.as_view(), name='establishment-admin-list'), path('menus/dishes/', views.MenuDishesListView.as_view(), name='menu-dishes-list'), + path('menus/dishes/create/', views.MenuDishesCreateView.as_view(), name='menu-dishes-create'), path('menus/dishes//', views.MenuDishesRUDView.as_view(), name='menu-dishes-rud'), + path('menus/dishes/slug//', views.MenuDishesRUDView.as_view(), name='menu-dishes-rud'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus//', views.MenuRUDView.as_view(), name='menu-rud'), path('menus/slug//', views.MenuRUDView.as_view(), name='menu-rud'), diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index d1384b1e..39ede5c3 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -1,5 +1,6 @@ """Establishment app views.""" - +from django.db.models.query_utils import Q +from django.http import Http404 from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend from rest_framework import generics, permissions @@ -14,6 +15,20 @@ from utils.permissions import IsCountryAdmin, IsEstablishmentManager, IsWineryRe from utils.views import CreateDestroyGalleryViewMixin +class MenuRUDMixinViews: + """Menu mixin""" + + def get_object(self): + instance = self.get_queryset().filter( + Q(establishment__slug=self.kwargs.get('slug')) | Q(establishment__id=self.kwargs.get('pk')) + ).first() + + if instance is None: + raise Http404 + + return instance + + class EstablishmentMixinViews: """Establishment mixin.""" @@ -121,7 +136,7 @@ class MenuListCreateView(generics.ListCreateAPIView): permission_classes = [IsWineryReviewer | IsEstablishmentManager] filter_backends = (DjangoFilterBackend,) filterset_fields = ( - 'establishment', + 'establishment__id', 'establishment__slug', ) @@ -129,8 +144,10 @@ class MenuListCreateView(generics.ListCreateAPIView): return super().get_queryset().prefetch_related('establishment') -class MenuRUDView(generics.RetrieveUpdateDestroyAPIView): +class MenuRUDView(MenuRUDMixinViews, generics.RetrieveUpdateDestroyAPIView): """Menu RUD view.""" + + lookup_field = None serializer_class = serializers.MenuRUDSerializers queryset = models.Menu.objects.all() permission_classes = [IsWineryReviewer | IsEstablishmentManager] @@ -469,13 +486,23 @@ class EstablishmentAdminView(generics.ListAPIView): class MenuDishesListView(generics.ListAPIView): """Menu (dessert, main_course, starter) list create view.""" serializer_class = serializers.MenuDishesSerializer - queryset = models.Menu.objects.all() + queryset = models.Menu.objects.with_dishes() permission_classes = [IsWineryReviewer | IsEstablishmentManager] filter_class = filters.MenuDishesBackFilter -class MenuDishesRUDView(generics.RetrieveUpdateDestroyAPIView): +class MenuDishesRUDView(MenuRUDMixinViews, generics.RetrieveUpdateDestroyAPIView): """Menu (dessert, main_course, starter) RUD view.""" + + lookup_field = None serializer_class = serializers.MenuDishesRUDSerializers - queryset = models.Menu.objects.all() + queryset = models.Menu.objects.with_dishes() permission_classes = [IsWineryReviewer | IsEstablishmentManager] + + +class MenuDishesCreateView(generics.CreateAPIView): + """Menu (dessert, main_course, starter) list create view.""" + serializer_class = serializers.MenuDishesCreateSerializer + queryset = models.MenuDish.objects.all() + permission_classes = [IsWineryReviewer | IsEstablishmentManager] + filter_class = filters.MenuDishesBackFilter From 007ba58f7a7e27d67fa149988b389411d424c4d0 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 18:22:58 +0300 Subject: [PATCH 093/101] partners create/fetch view --- apps/partner/serializers/back.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/partner/serializers/back.py b/apps/partner/serializers/back.py index 23c43787..a9e9bfa1 100644 --- a/apps/partner/serializers/back.py +++ b/apps/partner/serializers/back.py @@ -22,8 +22,7 @@ class BackPartnerSerializer(serializers.ModelSerializer): fields = ( 'id', 'name', - 'url', - # 'image', + 'images', 'type', 'type_display', 'starting_date', From e9646acfe1385a0c09841b19bf8f1a2101fe4f4d Mon Sep 17 00:00:00 2001 From: dormantman Date: Wed, 29 Jan 2020 18:38:15 +0300 Subject: [PATCH 094/101] Add migration --- .../migrations/0086_auto_20200129_1301.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 apps/establishment/migrations/0086_auto_20200129_1301.py diff --git a/apps/establishment/migrations/0086_auto_20200129_1301.py b/apps/establishment/migrations/0086_auto_20200129_1301.py new file mode 100644 index 00000000..99ad4d31 --- /dev/null +++ b/apps/establishment/migrations/0086_auto_20200129_1301.py @@ -0,0 +1,47 @@ +# Generated by Django 2.2.7 on 2020-01-29 13:01 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import utils.models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('establishment', '0085_menu_price'), + ] + + operations = [ + migrations.AlterField( + model_name='menufiles', + name='type', + field=models.CharField(choices=[('image', 'Image'), ('file', 'File')], default='', max_length=65, verbose_name='type'), + ), + migrations.CreateModel( + name='MenuDish', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('name', models.CharField(default='', max_length=255, verbose_name='name')), + ('category', utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='category')), + ('price', models.IntegerField(blank=True, default=None, null=True, verbose_name='price')), + ('signature', models.BooleanField(default=False, verbose_name='signature')), + ('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='menudish_records_created', to=settings.AUTH_USER_MODEL, verbose_name='created by')), + ('modified_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='menudish_records_modified', to=settings.AUTH_USER_MODEL, verbose_name='modified by')), + ], + options={ + 'verbose_name': 'dish', + 'verbose_name_plural': 'dishes', + 'ordering': ('-created',), + }, + ), + migrations.AddField( + model_name='menu', + name='dishes', + field=models.ManyToManyField(blank=True, to='establishment.MenuDish', verbose_name='Menu dishes'), + ), + ] From 0261deb5dff7ecda6f092853a5a341f19ce34b7c Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 19:18:09 +0300 Subject: [PATCH 095/101] get partners by establishment --- apps/partner/serializers/back.py | 32 +++++++++++++++++++++++++++++--- apps/partner/urls/back.py | 1 + apps/partner/views/back.py | 13 ++++++++++++- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/apps/partner/serializers/back.py b/apps/partner/serializers/back.py index a9e9bfa1..fb424970 100644 --- a/apps/partner/serializers/back.py +++ b/apps/partner/serializers/back.py @@ -1,13 +1,13 @@ """Back account serializers""" from rest_framework import serializers -from partner.models import Partner +from partner.models import Partner, PartnerToEstablishment from establishment.serializers import EstablishmentShortSerializer from location.serializers import CountrySimpleSerializer from location.models import Country class BackPartnerSerializer(serializers.ModelSerializer): - establishments = EstablishmentShortSerializer(many=True, read_only=True, source='establishment') + # establishments = EstablishmentShortSerializer(many=True, read_only=True, source='establishment') country = CountrySimpleSerializer(read_only=True) type_display = serializers.CharField(read_only=True) country_id = serializers.PrimaryKeyRelatedField( @@ -30,13 +30,39 @@ class BackPartnerSerializer(serializers.ModelSerializer): 'price_per_month', 'country', 'country_id', - 'establishments', + # 'establishments', ) extra_kwargs = { 'type': {'write_only': True}, } +class PartnersForEstablishmentSerializer(serializers.ModelSerializer): + id = serializers.IntegerField(source='partner.pk') + name = serializers.CharField(source='partner.name') + type = serializers.IntegerField(source='partner.type') + type_display = serializers.CharField(source='partner.type_display') + starting_date = serializers.DateField(source='partner.starting_date') + expiry_date = serializers.DateField(source='partner.expiry_date') + price_per_month = serializers.DecimalField(source='partner.price_per_month', max_digits=10, decimal_places=2) + country = CountrySimpleSerializer(read_only=True, source='partner.country') + + class Meta: + model = PartnerToEstablishment + fields = ( + 'id', + 'name', + 'type', + 'type_display', + 'starting_date', + 'expiry_date', + 'price_per_month', + 'country', + 'url', + 'image', + ) + + class PartnerPicturesSerializer(serializers.ModelSerializer): class Meta: diff --git a/apps/partner/urls/back.py b/apps/partner/urls/back.py index cc6bed24..3d13e623 100644 --- a/apps/partner/urls/back.py +++ b/apps/partner/urls/back.py @@ -8,6 +8,7 @@ app_name = 'partner' urlpatterns = [ path('', views.PartnerLstView.as_view(), name='partner-list-create'), path('/', views.PartnerRUDView.as_view(), name='partner-rud'), + path('for_establishment//', views.EstablishmentPartners.as_view(), name='partners-for-establishment'), path('pictures//', views.PartnerPicturesListView.as_view(), name='partner-pictures-get'), # path('bind///', views.BindPartnerToEstablishmentView.as_view(), # name='bind-partner-to-establishment'), diff --git a/apps/partner/views/back.py b/apps/partner/views/back.py index 4d51e76a..1594b7cf 100644 --- a/apps/partner/views/back.py +++ b/apps/partner/views/back.py @@ -1,7 +1,7 @@ from rest_framework import generics, permissions from partner import filters -from partner.models import Partner +from partner.models import Partner, PartnerToEstablishment from partner.serializers import back as serializers from utils.permissions import IsEstablishmentManager @@ -18,6 +18,17 @@ class PartnerLstView(generics.ListCreateAPIView): filter_class = filters.PartnerFilterSet +class EstablishmentPartners(generics.ListAPIView): + queryset = PartnerToEstablishment.objects.all() + serializer_class = serializers.PartnersForEstablishmentSerializer + pagination_class = None + permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] + # filter_class = filters.PartnerFilterSet + + def get_queryset(self): + return super().get_queryset().filter(establishment=self.kwargs['establishment_id']) + + class PartnerRUDView(generics.RetrieveUpdateDestroyAPIView): """Partner RUD view.""" queryset = Partner.objects.with_base_related() From 5ad32ad8aaadb78e21ab4ef971b1ce6d3b644770 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 19:59:11 +0300 Subject: [PATCH 096/101] partner bind/unbind --- apps/partner/serializers/back.py | 31 ++++++++++++++++++++++--------- apps/partner/urls/back.py | 11 ++++++----- apps/partner/views/back.py | 24 ++++++++++++++---------- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/apps/partner/serializers/back.py b/apps/partner/serializers/back.py index fb424970..09341f78 100644 --- a/apps/partner/serializers/back.py +++ b/apps/partner/serializers/back.py @@ -4,6 +4,8 @@ from partner.models import Partner, PartnerToEstablishment from establishment.serializers import EstablishmentShortSerializer from location.serializers import CountrySimpleSerializer from location.models import Country +from django.shortcuts import get_object_or_404 +from establishment.models import Establishment class BackPartnerSerializer(serializers.ModelSerializer): @@ -38,13 +40,14 @@ class BackPartnerSerializer(serializers.ModelSerializer): class PartnersForEstablishmentSerializer(serializers.ModelSerializer): - id = serializers.IntegerField(source='partner.pk') - name = serializers.CharField(source='partner.name') - type = serializers.IntegerField(source='partner.type') - type_display = serializers.CharField(source='partner.type_display') - starting_date = serializers.DateField(source='partner.starting_date') - expiry_date = serializers.DateField(source='partner.expiry_date') - price_per_month = serializers.DecimalField(source='partner.price_per_month', max_digits=10, decimal_places=2) + id = serializers.IntegerField(source='partner.pk', read_only=True) + name = serializers.CharField(source='partner.name', read_only=True) + type = serializers.IntegerField(source='partner.type', read_only=True) + type_display = serializers.CharField(source='partner.type_display', read_only=True) + starting_date = serializers.DateField(source='partner.starting_date', read_only=True) + expiry_date = serializers.DateField(source='partner.expiry_date', read_only=True) + price_per_month = serializers.DecimalField(source='partner.price_per_month', max_digits=10, decimal_places=2, + read_only=True) country = CountrySimpleSerializer(read_only=True, source='partner.country') class Meta: @@ -58,10 +61,20 @@ class PartnersForEstablishmentSerializer(serializers.ModelSerializer): 'expiry_date', 'price_per_month', 'country', - 'url', - 'image', + 'url', # own field + 'image', # own field ) + def create(self, validated_data): + establishment_id = self.context['view'].kwargs['establishment_id'] + partner_id = self.context['view'].kwargs['partner_id'] + establishment = get_object_or_404(Establishment, pk=establishment_id) + partner = get_object_or_404(Partner, pk=partner_id) + instance = PartnerToEstablishment.objects.create(**validated_data, + establishment=establishment, + partner=partner) + return instance + class PartnerPicturesSerializer(serializers.ModelSerializer): diff --git a/apps/partner/urls/back.py b/apps/partner/urls/back.py index 3d13e623..94829235 100644 --- a/apps/partner/urls/back.py +++ b/apps/partner/urls/back.py @@ -8,10 +8,11 @@ app_name = 'partner' urlpatterns = [ path('', views.PartnerLstView.as_view(), name='partner-list-create'), path('/', views.PartnerRUDView.as_view(), name='partner-rud'), - path('for_establishment//', views.EstablishmentPartners.as_view(), name='partners-for-establishment'), + path('for_establishment//', views.EstablishmentPartners.as_view(), + name='partners-for-establishment'), path('pictures//', views.PartnerPicturesListView.as_view(), name='partner-pictures-get'), - # path('bind///', views.BindPartnerToEstablishmentView.as_view(), - # name='bind-partner-to-establishment'), - # path('unbind///', views.BindPartnerToEstablishmentView.as_view(), - # name='unbind-partner-from-establishment'), + path('bind///', views.BindPartnerToEstablishmentView.as_view(), + name='bind-partner-to-establishment'), + path('unbind///', views.UnbindPartnerFromEstablishmentView.as_view(), + name='unbind-partner-from-establishment'), ] diff --git a/apps/partner/views/back.py b/apps/partner/views/back.py index 1594b7cf..eb35ddf0 100644 --- a/apps/partner/views/back.py +++ b/apps/partner/views/back.py @@ -1,5 +1,6 @@ from rest_framework import generics, permissions +from django.shortcuts import get_object_or_404 from partner import filters from partner.models import Partner, PartnerToEstablishment from partner.serializers import back as serializers @@ -14,7 +15,6 @@ class PartnerLstView(generics.ListCreateAPIView): serializer_class = serializers.BackPartnerSerializer pagination_class = None permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] - # permission_classes = (permissions.AllowAny, ) filter_class = filters.PartnerFilterSet @@ -23,7 +23,6 @@ class EstablishmentPartners(generics.ListAPIView): serializer_class = serializers.PartnersForEstablishmentSerializer pagination_class = None permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] - # filter_class = filters.PartnerFilterSet def get_queryset(self): return super().get_queryset().filter(establishment=self.kwargs['establishment_id']) @@ -34,7 +33,6 @@ class PartnerRUDView(generics.RetrieveUpdateDestroyAPIView): queryset = Partner.objects.with_base_related() serializer_class = serializers.BackPartnerSerializer permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] - # permission_classes = (permissions.AllowAny, ) lookup_field = 'id' @@ -42,12 +40,18 @@ class PartnerPicturesListView(generics.RetrieveAPIView): lookup_field = 'id' serializer_class = serializers.PartnerPicturesSerializer queryset = Partner.objects.with_base_related() - # permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] - permission_classes = (permissions.AllowAny, ) - -# class BindPartnerToEstablishmentView(generics.GenericAPIView): -# pass + permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] -# class UnbindPartnerFromEstablishmentView(generics.DestroyAPIView): -# pass +class BindPartnerToEstablishmentView(generics.CreateAPIView): + serializer_class = serializers.PartnersForEstablishmentSerializer + permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] + + +class UnbindPartnerFromEstablishmentView(generics.DestroyAPIView): + serializer_class = serializers.PartnersForEstablishmentSerializer + permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] + + def get_object(self): + return get_object_or_404(PartnerToEstablishment, establishment_id=self.kwargs['establishment_id'], + partner_id=self.kwargs['partner_id']) From 8eb828e30925675a7a4a903efe4633050bd070a2 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 20:44:42 +0300 Subject: [PATCH 097/101] partners remastered (sotring and optimization improvement) --- apps/partner/views/back.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/partner/views/back.py b/apps/partner/views/back.py index eb35ddf0..53182b92 100644 --- a/apps/partner/views/back.py +++ b/apps/partner/views/back.py @@ -1,6 +1,8 @@ -from rest_framework import generics, permissions - from django.shortcuts import get_object_or_404 +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework import generics, permissions +from rest_framework.filters import OrderingFilter + from partner import filters from partner.models import Partner, PartnerToEstablishment from partner.serializers import back as serializers @@ -19,10 +21,13 @@ class PartnerLstView(generics.ListCreateAPIView): class EstablishmentPartners(generics.ListAPIView): - queryset = PartnerToEstablishment.objects.all() + queryset = PartnerToEstablishment.objects.prefetch_related('partner', 'partner__country') serializer_class = serializers.PartnersForEstablishmentSerializer pagination_class = None permission_classes = [permissions.IsAdminUser | IsEstablishmentManager] + filter_backends = (OrderingFilter, DjangoFilterBackend) + ordering_fields = '__all__' + ordering = '-partner_bind_date' def get_queryset(self): return super().get_queryset().filter(establishment=self.kwargs['establishment_id']) From f3ca4a8de9eb192be039bc9493fa0658351aa2d9 Mon Sep 17 00:00:00 2001 From: "a.gorbunov" Date: Wed, 29 Jan 2020 18:20:21 +0000 Subject: [PATCH 098/101] place method to user class --- apps/account/models.py | 9 +++++++++ apps/account/serializers/back.py | 8 ++++++-- apps/account/serializers/common.py | 18 ------------------ 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/apps/account/models.py b/apps/account/models.py index 08944f0c..77f4d951 100644 --- a/apps/account/models.py +++ b/apps/account/models.py @@ -435,6 +435,15 @@ class User(AbstractUser): result.append(item.id) return set(result) + def set_roles(self, ids: set): + """ + Set user roles + :param ids: list of role ids + :return: bool + """ + self.roles.set(Role.objects.filter(id__in=ids)) + return self + class UserRoleQueryset(models.QuerySet): """QuerySet for model UserRole.""" diff --git a/apps/account/serializers/back.py b/apps/account/serializers/back.py index 4fba1c6f..af1029b5 100644 --- a/apps/account/serializers/back.py +++ b/apps/account/serializers/back.py @@ -2,7 +2,7 @@ from rest_framework import serializers from account import models -from account.serializers import RoleBaseSerializer, UserSerializer, subscriptions_handler, roles_handler +from account.serializers import RoleBaseSerializer, UserSerializer, subscriptions_handler from main.models import SiteSettings @@ -133,7 +133,11 @@ class BackDetailUserSerializer(BackUserSerializer): subscriptions_list = validated_data.pop('subscription_types') if 'roles' in validated_data: - instance = roles_handler(validated_data.pop('roles'), instance) + roles_ids = filter( + lambda filter_role: False if not filter_role else True, + map(lambda role: role["id"] if "id" in role else None, validated_data.pop("roles")) + ) + instance.set_roles(roles_ids) instance = super().update(instance, validated_data) subscriptions_handler(subscriptions_list, instance) diff --git a/apps/account/serializers/common.py b/apps/account/serializers/common.py index 790cbfdf..7ae6cb70 100644 --- a/apps/account/serializers/common.py +++ b/apps/account/serializers/common.py @@ -17,24 +17,6 @@ from utils.methods import generate_string_code from phonenumber_field.serializerfields import PhoneNumberField -def roles_handler(roles_list: set, user: User) -> User: - """ - Sync roles for user - :param roles_list: list of user roles - :param user: user - :return: bool - """ - if not roles_list: - user.roles.clear() - return user - - ids = list(map(lambda role: role["id"] if "id" in role else None, roles_list)) - roles = Role.objects \ - .filter(id__in=ids) - user.roles.set(roles) - return user - - def subscriptions_handler(subscriptions_list, user): """ create or update subscriptions for user From 62c25ac737cc5a1aa90ff35d828dd9aef9851730 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 22:49:36 +0300 Subject: [PATCH 099/101] simplify code --- apps/account/models.py | 3 ++- apps/account/serializers/back.py | 5 +---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/account/models.py b/apps/account/models.py index 77f4d951..e67fef49 100644 --- a/apps/account/models.py +++ b/apps/account/models.py @@ -13,6 +13,7 @@ from django.utils.http import urlsafe_base64_encode from django.utils.translation import ugettext_lazy as _ from rest_framework.authtoken.models import Token from collections import Counter +from typing import List from authorization.models import Application from establishment.models import Establishment, EstablishmentSubType @@ -435,7 +436,7 @@ class User(AbstractUser): result.append(item.id) return set(result) - def set_roles(self, ids: set): + def set_roles(self, ids: List(int)): """ Set user roles :param ids: list of role ids diff --git a/apps/account/serializers/back.py b/apps/account/serializers/back.py index af1029b5..93e33fa1 100644 --- a/apps/account/serializers/back.py +++ b/apps/account/serializers/back.py @@ -133,10 +133,7 @@ class BackDetailUserSerializer(BackUserSerializer): subscriptions_list = validated_data.pop('subscription_types') if 'roles' in validated_data: - roles_ids = filter( - lambda filter_role: False if not filter_role else True, - map(lambda role: role["id"] if "id" in role else None, validated_data.pop("roles")) - ) + roles_ids = [role['id'] for role in validated_data.pop('roles') if 'id' in role] instance.set_roles(roles_ids) instance = super().update(instance, validated_data) From a2e200b48dfcf5eada1f39535df631bb66a4a43e Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 29 Jan 2020 22:53:28 +0300 Subject: [PATCH 100/101] fix typing --- apps/account/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/account/models.py b/apps/account/models.py index e67fef49..96a4916c 100644 --- a/apps/account/models.py +++ b/apps/account/models.py @@ -436,7 +436,7 @@ class User(AbstractUser): result.append(item.id) return set(result) - def set_roles(self, ids: List(int)): + def set_roles(self, ids: List[int]): """ Set user roles :param ids: list of role ids From 214c5797015c24a35696c53c8d35a82a1e3ca70b Mon Sep 17 00:00:00 2001 From: dormantman Date: Thu, 30 Jan 2020 04:24:29 +0300 Subject: [PATCH 101/101] Update django locales (for subscriptions) --- project/locale/fr/LC_MESSAGES/django.mo | Bin 534 -> 1154 bytes project/locale/fr/LC_MESSAGES/django.po | 543 ++++++++++++------------ project/locale/ru/LC_MESSAGES/django.mo | Bin 888 -> 1617 bytes project/locale/ru/LC_MESSAGES/django.po | 543 ++++++++++++------------ 4 files changed, 558 insertions(+), 528 deletions(-) diff --git a/project/locale/fr/LC_MESSAGES/django.mo b/project/locale/fr/LC_MESSAGES/django.mo index 70828c7eaaa31f603456a522442c99aa86afd8c1..30f3e716ca47c118a124affff86088f01ae27819 100644 GIT binary patch literal 1154 zcmZXS%WfMt6o%O*X%e+XkSq!mP0-UUf))mITLojw$;2KxLL|$OWTP&S1vNuUv`6HW z7x{v0^9TXD>?RB4HS`We7eSt(yDrn8BNR4}18_bL=bZnX0soJ;F27}nZ?JA-y~etU z^#LmeeZkmu@Fy^yuYf;*O>hO=2Y&?LfDgfU;P>EP;8);3;J4tvVAQ$tlpynhz|sg z>wmoh#yZH=`PaZ07^jY?RY%K|r8%bH*w(!+4Z_IfR#jdZ?bvXl9LcFrB~65*k(8R8 z)SkRy`zBB>G>Os~RFlzUf+c5iB}&rL9~*mw5{TEi6ETzImhvN6#C$D}9ii*R?|Ckr zI|yZYN5ww{5#hj#`nNx7_C)+dd zOl86hB8&N0lyxQPc5M_kco`t2n6ryo}`{pDgAun_ij?``T)t L3sq&+6ubWbIWk7} delta 151 zcmZqToW@drPl#nI0}!wRu?!Hq05Lld=KwJXbO13M5O)GGFAz@vVoo5Q2gD%p6+rCB z$iT23%Kr#ta|78wfHcS)7AA;#9v}@A0^7q3q=8%z;ACKdFc>z!XUt@r9Lu5#07JSB AUH||9 diff --git a/project/locale/fr/LC_MESSAGES/django.po b/project/locale/fr/LC_MESSAGES/django.po index 6fcf4319..33f93c00 100644 --- a/project/locale/fr/LC_MESSAGES/django.po +++ b/project/locale/fr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-01-28 15:17+0000\n" +"POT-Creation-Date: 2020-01-30 01:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -34,7 +34,7 @@ msgstr "" msgid "Permissions" msgstr "" -#: apps/account/admin.py:61 apps/establishment/models.py:1101 +#: apps/account/admin.py:61 apps/establishment/models.py:1103 #: apps/location/models.py:41 apps/product/models.py:49 #: apps/product/models.py:87 msgid "Name" @@ -60,181 +60,180 @@ msgstr "" msgid "New password confirmation" msgstr "" -#: apps/account/models.py:56 +#: apps/account/models.py:57 msgid "Standard user" msgstr "" -#: apps/account/models.py:57 +#: apps/account/models.py:58 msgid "Comments moderator" msgstr "" -#: apps/account/models.py:58 +#: apps/account/models.py:59 msgid "Country admin" msgstr "" -#: apps/account/models.py:59 +#: apps/account/models.py:60 msgid "Content page manager" msgstr "" -#: apps/account/models.py:60 +#: apps/account/models.py:61 msgid "Establishment manager" msgstr "" -#: apps/account/models.py:61 +#: apps/account/models.py:62 msgid "Reviewer manager" msgstr "" -#: apps/account/models.py:62 +#: apps/account/models.py:63 msgid "Restaurant reviewer" msgstr "" -#: apps/account/models.py:63 +#: apps/account/models.py:64 msgid "Sales man" msgstr "" -#: apps/account/models.py:64 +#: apps/account/models.py:65 msgid "Winery reviewer" msgstr "" -#: apps/account/models.py:65 +#: apps/account/models.py:66 msgid "Seller" msgstr "" -#: apps/account/models.py:66 +#: apps/account/models.py:67 msgid "Liquor reviewer" msgstr "" -#: apps/account/models.py:67 +#: apps/account/models.py:68 msgid "Product reviewer" msgstr "" -#: apps/account/models.py:70 apps/account/models.py:501 +#: apps/account/models.py:71 apps/account/models.py:511 msgid "Role" msgstr "" -#: apps/account/models.py:72 apps/establishment/models.py:1420 +#: apps/account/models.py:73 apps/establishment/models.py:1425 #: apps/location/models.py:57 apps/main/models.py:61 apps/review/models.py:57 msgid "Country" msgstr "" -#: apps/account/models.py:74 apps/main/models.py:88 +#: apps/account/models.py:75 apps/main/models.py:88 msgid "Site settings" msgstr "" -#: apps/account/models.py:77 apps/establishment/models.py:112 +#: apps/account/models.py:78 apps/establishment/models.py:111 msgid "Establishment subtype" msgstr "" -#: apps/account/models.py:83 +#: apps/account/models.py:84 msgid "navigation bar permission" msgstr "" -#: apps/account/models.py:207 +#: apps/account/models.py:208 msgid "username" msgstr "" -#: apps/account/models.py:210 +#: apps/account/models.py:211 msgid "Required. 150 characters or fewer. Letters, digits and ./+/-/_ only." msgstr "" -#: apps/account/models.py:212 +#: apps/account/models.py:213 msgid "A user with that username already exists." msgstr "" -#: apps/account/models.py:215 apps/news/models.py:49 apps/utils/models.py:270 +#: apps/account/models.py:216 apps/news/models.py:49 apps/utils/models.py:299 msgid "Image URL path" msgstr "" -#: apps/account/models.py:218 +#: apps/account/models.py:219 msgid "Cropped image URL path" msgstr "" -#: apps/account/models.py:220 +#: apps/account/models.py:221 msgid "email address" msgstr "" -#: apps/account/models.py:222 +#: apps/account/models.py:223 msgid "unconfirmed email" msgstr "" -#: apps/account/models.py:223 +#: apps/account/models.py:224 msgid "email status" msgstr "" -#: apps/account/models.py:227 +#: apps/account/models.py:228 msgid "User last used locale" msgstr "" -#: apps/account/models.py:229 +#: apps/account/models.py:230 msgid "User last visited from city" msgstr "" -#: apps/account/models.py:230 +#: apps/account/models.py:231 msgid "last IP address" msgstr "" -#: apps/account/models.py:233 +#: apps/account/models.py:234 msgid "last site settings" msgstr "" -#: apps/account/models.py:240 +#: apps/account/models.py:241 msgid "Phone" msgstr "" -#: apps/account/models.py:247 +#: apps/account/models.py:248 msgid "Roles" msgstr "" -#: apps/account/models.py:253 apps/account/models.py:499 -#: apps/comment/models.py:74 apps/establishment/models.py:1100 +#: apps/account/models.py:254 apps/account/models.py:509 +#: apps/comment/models.py:74 apps/establishment/models.py:1102 #: apps/favorites/models.py:23 apps/notification/models.py:104 msgid "User" msgstr "" -#: apps/account/models.py:254 +#: apps/account/models.py:255 msgid "Users" msgstr "" -#: apps/account/models.py:492 +#: apps/account/models.py:502 msgid "validated" msgstr "" -#: apps/account/models.py:493 +#: apps/account/models.py:503 msgid "pending" msgstr "" -#: apps/account/models.py:494 +#: apps/account/models.py:504 msgid "cancelled" msgstr "" -#: apps/account/models.py:495 +#: apps/account/models.py:505 msgid "rejected" msgstr "" -#: apps/account/models.py:503 apps/establishment/apps.py:8 -#: apps/establishment/models.py:614 apps/establishment/models.py:975 -#: apps/partner/models.py:24 +#: apps/account/models.py:513 apps/establishment/apps.py:8 +#: apps/establishment/models.py:613 apps/establishment/models.py:977 msgid "Establishment" msgstr "" -#: apps/account/models.py:507 apps/collection/models.py:280 +#: apps/account/models.py:517 apps/collection/models.py:317 #: apps/product/models.py:293 msgid "state" msgstr "" -#: apps/account/models.py:521 +#: apps/account/models.py:531 msgid "New role" msgstr "" -#: apps/account/models.py:522 +#: apps/account/models.py:532 msgid "Old role" msgstr "" -#: apps/account/serializers/common.py:226 +#: apps/account/serializers/common.py:230 msgid "Old password mismatch." msgstr "" -#: apps/account/serializers/common.py:229 apps/utils/exceptions.py:103 +#: apps/account/serializers/common.py:233 apps/utils/exceptions.py:103 msgid "Password is already in use" msgstr "" @@ -242,13 +241,13 @@ msgstr "" msgid "advertisement" msgstr "" -#: apps/advertisement/models.py:43 apps/collection/models.py:748 -#: apps/collection/models.py:968 apps/establishment/models.py:527 -#: apps/establishment/models.py:1288 apps/establishment/models.py:1353 +#: apps/advertisement/models.py:43 apps/collection/models.py:785 +#: apps/collection/models.py:1005 apps/establishment/models.py:526 +#: apps/establishment/models.py:1321 apps/establishment/models.py:1358 #: apps/location/models.py:286 apps/location/models.py:317 #: apps/location/models.py:344 apps/main/models.py:258 apps/main/models.py:443 #: apps/news/models.py:283 apps/notification/models.py:118 -#: apps/partner/models.py:18 apps/product/models.py:289 +#: apps/partner/models.py:33 apps/product/models.py:289 #: apps/product/models.py:526 apps/product/models.py:592 #: apps/recipe/models.py:61 apps/review/models.py:90 apps/review/models.py:130 #: apps/review/models.py:158 apps/review/models.py:175 apps/tag/models.py:45 @@ -264,7 +263,7 @@ msgid "Block level" msgstr "" #: apps/advertisement/models.py:48 apps/collection/models.py:39 -#: apps/collection/models.py:269 +#: apps/collection/models.py:306 msgid "start" msgstr "" @@ -383,13 +382,14 @@ msgid "collection" msgstr "" #: apps/collection/models.py:29 apps/collection/models.py:78 -#: apps/collection/models.py:690 apps/establishment/models.py:528 -#: apps/establishment/models.py:1214 apps/establishment/models.py:1450 -#: apps/location/models.py:101 apps/location/models.py:280 -#: apps/location/models.py:313 apps/location/models.py:341 -#: apps/main/models.py:32 apps/main/models.py:223 apps/main/models.py:386 -#: apps/main/models.py:428 apps/news/models.py:64 -#: apps/notification/models.py:20 apps/partner/models.py:19 +#: apps/collection/models.py:727 apps/establishment/models.py:527 +#: apps/establishment/models.py:1216 apps/establishment/models.py:1251 +#: apps/establishment/models.py:1296 apps/establishment/models.py:1338 +#: apps/establishment/models.py:1455 apps/location/models.py:101 +#: apps/location/models.py:280 apps/location/models.py:313 +#: apps/location/models.py:341 apps/main/models.py:32 apps/main/models.py:223 +#: apps/main/models.py:386 apps/main/models.py:428 apps/news/models.py:64 +#: apps/notification/models.py:20 apps/partner/models.py:34 #: apps/product/models.py:260 apps/product/models.py:490 #: apps/product/models.py:521 apps/review/models.py:161 msgid "name" @@ -408,7 +408,7 @@ msgid "Collection type" msgstr "" #: apps/collection/models.py:84 apps/comment/models.py:76 -#: apps/establishment/models.py:574 +#: apps/establishment/models.py:573 msgid "Publish status" msgstr "" @@ -427,8 +427,8 @@ msgstr "" msgid "collection block properties" msgstr "" -#: apps/collection/models.py:93 apps/establishment/models.py:535 -#: apps/establishment/models.py:1217 apps/location/models.py:289 +#: apps/collection/models.py:93 apps/establishment/models.py:534 +#: apps/establishment/models.py:1219 apps/location/models.py:289 #: apps/main/models.py:434 apps/news/models.py:295 apps/product/models.py:261 #: apps/review/models.py:163 msgid "description" @@ -442,165 +442,165 @@ msgstr "" msgid "collections" msgstr "" -#: apps/collection/models.py:260 +#: apps/collection/models.py:297 msgid "Restaurant" msgstr "" -#: apps/collection/models.py:261 +#: apps/collection/models.py:298 msgid "Artisan" msgstr "" -#: apps/collection/models.py:262 +#: apps/collection/models.py:299 msgid "Wine" msgstr "" -#: apps/collection/models.py:267 +#: apps/collection/models.py:304 msgid "guide type" msgstr "" -#: apps/collection/models.py:273 +#: apps/collection/models.py:310 msgid "guide vintage year" msgstr "" -#: apps/collection/models.py:275 +#: apps/collection/models.py:312 msgid "slug" msgstr "" -#: apps/collection/models.py:278 apps/news/models.py:336 +#: apps/collection/models.py:315 apps/news/models.py:336 msgid "site settings" msgstr "" -#: apps/collection/models.py:283 +#: apps/collection/models.py:320 msgid "* after rebuild guide, refresh count of related guide elements" msgstr "" -#: apps/collection/models.py:284 +#: apps/collection/models.py:321 msgid "count of related guide elements during initialization" msgstr "" -#: apps/collection/models.py:291 apps/collection/models.py:463 +#: apps/collection/models.py:328 apps/collection/models.py:500 msgid "guide" msgstr "" -#: apps/collection/models.py:292 +#: apps/collection/models.py:329 msgid "guides" msgstr "" -#: apps/collection/models.py:413 +#: apps/collection/models.py:450 msgid "number of pages" msgstr "" -#: apps/collection/models.py:414 +#: apps/collection/models.py:451 msgid "the total number of reserved pages" msgstr "" -#: apps/collection/models.py:416 +#: apps/collection/models.py:453 msgid "number of right pages" msgstr "" -#: apps/collection/models.py:417 +#: apps/collection/models.py:454 msgid "the number of right pages (which are part of total number)." msgstr "" -#: apps/collection/models.py:420 apps/collection/models.py:974 +#: apps/collection/models.py:457 apps/collection/models.py:1011 msgid "guide element" msgstr "" -#: apps/collection/models.py:427 +#: apps/collection/models.py:464 msgid "advertorial" msgstr "" -#: apps/collection/models.py:428 +#: apps/collection/models.py:465 msgid "advertorials" msgstr "" -#: apps/collection/models.py:449 +#: apps/collection/models.py:486 msgid "with mark" msgstr "" -#: apps/collection/models.py:450 +#: apps/collection/models.py:487 msgid "exclude empty marks?" msgstr "" -#: apps/collection/models.py:453 +#: apps/collection/models.py:490 msgid "max mark" msgstr "" -#: apps/collection/models.py:455 +#: apps/collection/models.py:492 msgid "mark under" msgstr "" -#: apps/collection/models.py:456 +#: apps/collection/models.py:493 msgid "min mark" msgstr "" -#: apps/collection/models.py:458 +#: apps/collection/models.py:495 msgid "mark over" msgstr "" -#: apps/collection/models.py:470 +#: apps/collection/models.py:507 msgid "guide filter" msgstr "" -#: apps/collection/models.py:471 +#: apps/collection/models.py:508 msgid "guide filters" msgstr "" -#: apps/collection/models.py:694 apps/collection/models.py:943 +#: apps/collection/models.py:731 apps/collection/models.py:980 msgid "guide element type" msgstr "" -#: apps/collection/models.py:695 +#: apps/collection/models.py:732 msgid "guide element types" msgstr "" -#: apps/collection/models.py:709 apps/collection/models.py:744 +#: apps/collection/models.py:746 apps/collection/models.py:781 msgid "section name" msgstr "" -#: apps/collection/models.py:715 +#: apps/collection/models.py:752 msgid "guide wine color section" msgstr "" -#: apps/collection/models.py:716 +#: apps/collection/models.py:753 msgid "guide wine color sections" msgstr "" -#: apps/collection/models.py:727 +#: apps/collection/models.py:764 msgid "category name" msgstr "" -#: apps/collection/models.py:733 +#: apps/collection/models.py:770 msgid "guide element section category" msgstr "" -#: apps/collection/models.py:734 +#: apps/collection/models.py:771 msgid "guide element section categories" msgstr "" -#: apps/collection/models.py:746 apps/establishment/admin.py:121 -#: apps/establishment/models.py:1276 +#: apps/collection/models.py:783 apps/establishment/admin.py:121 +#: apps/establishment/models.py:1253 apps/establishment/models.py:1318 msgid "category" msgstr "" -#: apps/collection/models.py:754 +#: apps/collection/models.py:791 msgid "guide element section" msgstr "" -#: apps/collection/models.py:755 +#: apps/collection/models.py:792 msgid "guide element sections" msgstr "" -#: apps/collection/models.py:966 +#: apps/collection/models.py:1003 msgid "label photo" msgstr "" -#: apps/collection/models.py:975 +#: apps/collection/models.py:1012 msgid "guide elements" msgstr "" -#: apps/collection/views/back.py:177 apps/collection/views/back.py:193 -#: apps/collection/views/back.py:209 apps/main/views/back.py:174 +#: apps/collection/views/back.py:168 apps/collection/views/back.py:184 +#: apps/collection/views/back.py:200 apps/main/views/back.py:174 #: apps/main/views/back.py:190 msgid "The file will be sent to your email." msgstr "" @@ -659,451 +659,458 @@ msgstr "" msgid "default language" msgstr "" -#: apps/establishment/filters.py:126 apps/news/filters.py:55 +#: apps/establishment/filters.py:125 apps/news/filters.py:55 msgid "Type at least 3 characters to search please." msgstr "" -#: apps/establishment/models.py:50 apps/establishment/models.py:91 -#: apps/establishment/models.py:935 apps/recipe/models.py:53 +#: apps/establishment/models.py:49 apps/establishment/models.py:90 +#: apps/establishment/models.py:937 apps/recipe/models.py:53 msgid "Description" msgstr "" -#: apps/establishment/models.py:53 apps/establishment/models.py:94 -#: apps/establishment/models.py:533 apps/establishment/models.py:941 +#: apps/establishment/models.py:52 apps/establishment/models.py:93 +#: apps/establishment/models.py:532 apps/establishment/models.py:943 #: apps/notification/models.py:18 apps/product/models.py:51 #: apps/product/models.py:89 msgid "Index name" msgstr "" -#: apps/establishment/models.py:54 apps/product/models.py:52 +#: apps/establishment/models.py:53 apps/product/models.py:52 msgid "Use subtypes" msgstr "" -#: apps/establishment/models.py:58 apps/establishment/models.py:101 +#: apps/establishment/models.py:57 apps/establishment/models.py:100 #: apps/product/models.py:56 apps/tag/models.py:176 msgid "Tag categories" msgstr "" -#: apps/establishment/models.py:67 +#: apps/establishment/models.py:66 msgid "Establishment type" msgstr "" -#: apps/establishment/models.py:68 +#: apps/establishment/models.py:67 msgid "Establishment types" msgstr "" -#: apps/establishment/models.py:97 apps/product/models.py:266 +#: apps/establishment/models.py:96 apps/product/models.py:266 msgid "Type" msgstr "" -#: apps/establishment/models.py:113 +#: apps/establishment/models.py:112 msgid "Establishment subtypes" msgstr "" -#: apps/establishment/models.py:117 +#: apps/establishment/models.py:116 msgid "Establishment type is not use subtypes." msgstr "" -#: apps/establishment/models.py:530 +#: apps/establishment/models.py:529 msgid "Transliterated name" msgstr "" -#: apps/establishment/models.py:532 +#: apps/establishment/models.py:531 msgid "Western name" msgstr "" -#: apps/establishment/models.py:539 apps/product/models.py:275 +#: apps/establishment/models.py:538 apps/product/models.py:275 msgid "public mark" msgstr "" -#: apps/establishment/models.py:543 +#: apps/establishment/models.py:542 msgid "toque number" msgstr "" -#: apps/establishment/models.py:547 +#: apps/establishment/models.py:546 apps/establishment/models.py:1339 msgid "type" msgstr "" -#: apps/establishment/models.py:551 +#: apps/establishment/models.py:550 msgid "subtype" msgstr "" -#: apps/establishment/models.py:554 apps/establishment/models.py:1473 +#: apps/establishment/models.py:553 apps/establishment/models.py:1478 #: apps/news/models.py:34 apps/news/models.py:315 msgid "address" msgstr "" -#: apps/establishment/models.py:557 +#: apps/establishment/models.py:556 msgid "price level" msgstr "" -#: apps/establishment/models.py:559 +#: apps/establishment/models.py:558 msgid "Web site URL" msgstr "" -#: apps/establishment/models.py:561 +#: apps/establishment/models.py:560 msgid "Facebook URL" msgstr "" -#: apps/establishment/models.py:563 +#: apps/establishment/models.py:562 msgid "Twitter URL" msgstr "" -#: apps/establishment/models.py:565 +#: apps/establishment/models.py:564 msgid "Instagram URL" msgstr "" -#: apps/establishment/models.py:567 +#: apps/establishment/models.py:566 msgid "Lafourchette URL" msgstr "" -#: apps/establishment/models.py:568 +#: apps/establishment/models.py:567 msgid "guestonline id" msgstr "" -#: apps/establishment/models.py:570 +#: apps/establishment/models.py:569 msgid "lastable id" msgstr "" -#: apps/establishment/models.py:573 +#: apps/establishment/models.py:572 msgid "Booking URL" msgstr "" -#: apps/establishment/models.py:576 apps/establishment/models.py:1285 +#: apps/establishment/models.py:575 msgid "Establishment schedule" msgstr "" -#: apps/establishment/models.py:579 +#: apps/establishment/models.py:578 msgid "Transportation" msgstr "" -#: apps/establishment/models.py:583 +#: apps/establishment/models.py:582 msgid "Collections" msgstr "" -#: apps/establishment/models.py:585 +#: apps/establishment/models.py:584 msgid "Preview image URL path" msgstr "" -#: apps/establishment/models.py:588 +#: apps/establishment/models.py:587 msgid "Establishment slug" msgstr "" -#: apps/establishment/models.py:593 apps/product/models.py:296 +#: apps/establishment/models.py:592 apps/product/models.py:296 #: apps/product/models.py:591 apps/tag/models.py:65 msgid "Tag" msgstr "" -#: apps/establishment/models.py:600 apps/establishment/models.py:1223 +#: apps/establishment/models.py:599 apps/establishment/models.py:1225 #: apps/main/models.py:39 msgid "currency" msgstr "" -#: apps/establishment/models.py:604 apps/product/models.py:483 +#: apps/establishment/models.py:603 apps/product/models.py:483 msgid "purchased plaques" msgstr "" -#: apps/establishment/models.py:605 +#: apps/establishment/models.py:604 msgid "" "Attribute from legacy db.\n" "Must be deleted after the implementation of the market." msgstr "" -#: apps/establishment/models.py:615 +#: apps/establishment/models.py:614 apps/partner/models.py:40 msgid "Establishments" msgstr "" -#: apps/establishment/models.py:896 apps/product/models.py:609 +#: apps/establishment/models.py:898 apps/product/models.py:609 #: apps/review/models.py:69 msgid "text" msgstr "" -#: apps/establishment/models.py:899 apps/establishment/models.py:917 -#: apps/establishment/models.py:1279 apps/establishment/models.py:1356 -#: apps/establishment/models.py:1449 apps/product/models.py:273 +#: apps/establishment/models.py:901 apps/establishment/models.py:919 +#: apps/establishment/models.py:1298 apps/establishment/models.py:1361 +#: apps/establishment/models.py:1454 apps/product/models.py:273 #: apps/product/models.py:472 msgid "establishment" msgstr "" -#: apps/establishment/models.py:903 apps/product/models.py:616 +#: apps/establishment/models.py:905 apps/product/models.py:616 #: apps/review/models.py:103 apps/review/models.py:138 msgid "author" msgstr "" -#: apps/establishment/models.py:909 +#: apps/establishment/models.py:911 msgid "establishment notes" msgstr "" -#: apps/establishment/models.py:910 +#: apps/establishment/models.py:912 msgid "establishment note" msgstr "" -#: apps/establishment/models.py:921 apps/establishment/models.py:1311 -#: apps/product/models.py:545 apps/review/models.py:188 +#: apps/establishment/models.py:923 apps/product/models.py:545 +#: apps/review/models.py:188 msgid "image" msgstr "" -#: apps/establishment/models.py:925 +#: apps/establishment/models.py:927 msgid "establishment gallery" msgstr "" -#: apps/establishment/models.py:926 +#: apps/establishment/models.py:928 msgid "establishment galleries" msgstr "" -#: apps/establishment/models.py:946 apps/establishment/models.py:983 +#: apps/establishment/models.py:948 apps/establishment/models.py:985 msgid "Position" msgstr "" -#: apps/establishment/models.py:947 +#: apps/establishment/models.py:949 msgid "Positions" msgstr "" -#: apps/establishment/models.py:977 apps/establishment/models.py:1140 +#: apps/establishment/models.py:979 apps/establishment/models.py:1142 msgid "Employee" msgstr "" -#: apps/establishment/models.py:978 +#: apps/establishment/models.py:980 msgid "From date" msgstr "" -#: apps/establishment/models.py:981 +#: apps/establishment/models.py:983 msgid "To date" msgstr "" -#: apps/establishment/models.py:988 apps/establishment/models.py:1128 +#: apps/establishment/models.py:990 apps/establishment/models.py:1130 msgid "Old id" msgstr "" -#: apps/establishment/models.py:1102 +#: apps/establishment/models.py:1104 msgid "Last Name" msgstr "" -#: apps/establishment/models.py:1110 +#: apps/establishment/models.py:1112 msgid "Male" msgstr "" -#: apps/establishment/models.py:1111 +#: apps/establishment/models.py:1113 msgid "Female" msgstr "" -#: apps/establishment/models.py:1113 +#: apps/establishment/models.py:1115 msgid "Sex" msgstr "" -#: apps/establishment/models.py:1115 +#: apps/establishment/models.py:1117 msgid "Birth date" msgstr "" -#: apps/establishment/models.py:1117 apps/notification/models.py:106 +#: apps/establishment/models.py:1119 apps/notification/models.py:106 msgid "Email" msgstr "" -#: apps/establishment/models.py:1119 +#: apps/establishment/models.py:1121 msgid "Toque number" msgstr "" -#: apps/establishment/models.py:1126 apps/news/models.py:321 +#: apps/establishment/models.py:1128 apps/news/models.py:321 #: apps/tag/models.py:66 msgid "Tags" msgstr "" -#: apps/establishment/models.py:1129 +#: apps/establishment/models.py:1131 msgid "Available for events" msgstr "" -#: apps/establishment/models.py:1133 apps/location/models.py:170 +#: apps/establishment/models.py:1135 apps/location/models.py:170 msgid "image instance of model Image" msgstr "" -#: apps/establishment/models.py:1141 +#: apps/establishment/models.py:1143 msgid "Employees" msgstr "" -#: apps/establishment/models.py:1188 +#: apps/establishment/models.py:1190 msgid "contact phone" msgstr "" -#: apps/establishment/models.py:1189 apps/establishment/models.py:1453 +#: apps/establishment/models.py:1191 apps/establishment/models.py:1458 msgid "contact phones" msgstr "" -#: apps/establishment/models.py:1202 +#: apps/establishment/models.py:1204 msgid "contact email" msgstr "" -#: apps/establishment/models.py:1203 +#: apps/establishment/models.py:1205 msgid "contact emails" msgstr "" -#: apps/establishment/models.py:1220 apps/review/models.py:141 +#: apps/establishment/models.py:1222 apps/establishment/models.py:1255 +#: apps/establishment/models.py:1301 apps/review/models.py:141 msgid "price" msgstr "" -#: apps/establishment/models.py:1221 +#: apps/establishment/models.py:1223 msgid "is signature plate" msgstr "" -#: apps/establishment/models.py:1226 +#: apps/establishment/models.py:1228 msgid "currency code" msgstr "" -#: apps/establishment/models.py:1230 apps/establishment/models.py:1293 -#: apps/establishment/models.py:1294 apps/establishment/models.py:1304 -#: apps/establishment/models.py:1326 +#: apps/establishment/models.py:1232 apps/establishment/models.py:1326 +#: apps/establishment/models.py:1327 msgid "menu" msgstr "" -#: apps/establishment/models.py:1240 +#: apps/establishment/models.py:1242 msgid "plate" msgstr "" -#: apps/establishment/models.py:1241 +#: apps/establishment/models.py:1243 msgid "plates" msgstr "" -#: apps/establishment/models.py:1281 +#: apps/establishment/models.py:1256 +msgid "signature" +msgstr "" + +#: apps/establishment/models.py:1259 +msgid "dish" +msgstr "" + +#: apps/establishment/models.py:1260 +msgid "dishes" +msgstr "" + +#: apps/establishment/models.py:1300 msgid "is drinks included" msgstr "" -#: apps/establishment/models.py:1316 -msgid "menu gallery" +#: apps/establishment/models.py:1305 +msgid "Menu schedule" msgstr "" -#: apps/establishment/models.py:1317 -msgid "menu galleries" +#: apps/establishment/models.py:1310 +msgid "Menu files" msgstr "" -#: apps/establishment/models.py:1330 apps/establishment/models.py:1342 -#: apps/gallery/models.py:29 apps/main/models.py:196 apps/main/models.py:402 -#: apps/news/models.py:47 apps/news/models.py:287 -msgid "title" +#: apps/establishment/models.py:1315 +msgid "Menu dishes" msgstr "" -#: apps/establishment/models.py:1332 -msgid "File" -msgstr "" - -#: apps/establishment/models.py:1337 +#: apps/establishment/models.py:1342 msgid "menu upload" msgstr "" -#: apps/establishment/models.py:1338 +#: apps/establishment/models.py:1343 msgid "menu uploads" msgstr "" -#: apps/establishment/models.py:1345 +#: apps/establishment/models.py:1347 apps/gallery/models.py:29 +#: apps/main/models.py:196 apps/main/models.py:402 apps/news/models.py:47 +#: apps/news/models.py:287 +msgid "title" +msgstr "" + +#: apps/establishment/models.py:1350 msgid "social choice" msgstr "" -#: apps/establishment/models.py:1346 +#: apps/establishment/models.py:1351 msgid "social choices" msgstr "" -#: apps/establishment/models.py:1362 apps/establishment/models.py:1369 +#: apps/establishment/models.py:1367 apps/establishment/models.py:1374 msgid "social network" msgstr "" -#: apps/establishment/models.py:1366 +#: apps/establishment/models.py:1371 msgid "URL" msgstr "" -#: apps/establishment/models.py:1370 +#: apps/establishment/models.py:1375 msgid "social networks" msgstr "" -#: apps/establishment/models.py:1411 +#: apps/establishment/models.py:1416 msgid "One" msgstr "" -#: apps/establishment/models.py:1412 +#: apps/establishment/models.py:1417 msgid "Two" msgstr "" -#: apps/establishment/models.py:1413 +#: apps/establishment/models.py:1418 msgid "Three" msgstr "" -#: apps/establishment/models.py:1414 +#: apps/establishment/models.py:1419 msgid "Four" msgstr "" -#: apps/establishment/models.py:1415 +#: apps/establishment/models.py:1420 msgid "Five" msgstr "" -#: apps/establishment/models.py:1430 apps/establishment/models.py:1431 +#: apps/establishment/models.py:1435 apps/establishment/models.py:1436 msgid "Rating strategy" msgstr "" -#: apps/establishment/models.py:1456 +#: apps/establishment/models.py:1461 msgid "fax numbers" msgstr "" -#: apps/establishment/models.py:1459 +#: apps/establishment/models.py:1464 msgid "legal entity" msgstr "" -#: apps/establishment/models.py:1462 +#: apps/establishment/models.py:1467 msgid "registry number" msgstr "" -#: apps/establishment/models.py:1465 +#: apps/establishment/models.py:1470 msgid "VAT identification number" msgstr "" -#: apps/establishment/models.py:1469 +#: apps/establishment/models.py:1474 msgid "sic code" msgstr "" -#: apps/establishment/models.py:1479 +#: apps/establishment/models.py:1484 msgid "company" msgstr "" -#: apps/establishment/models.py:1480 +#: apps/establishment/models.py:1485 msgid "companies" msgstr "" -#: apps/establishment/serializers/back.py:467 +#: apps/establishment/serializers/back.py:473 msgid "Establishment not found" msgstr "" -#: apps/establishment/serializers/back.py:470 -#: apps/establishment/serializers/back.py:680 apps/news/serializers.py:445 +#: apps/establishment/serializers/back.py:476 apps/news/serializers.py:431 #: apps/product/serializers/back.py:42 msgid "Image not found" msgstr "" -#: apps/establishment/serializers/back.py:476 +#: apps/establishment/serializers/back.py:482 #: apps/product/serializers/back.py:48 msgid "Image is already added." msgstr "" -#: apps/establishment/serializers/back.py:678 -msgid "Menu not found" -msgstr "" - -#: apps/establishment/serializers/common.py:212 +#: apps/establishment/serializers/common.py:270 #, python-brace-format msgid "{entity_class.__name__} not found." msgstr "" -#: apps/establishment/serializers/common.py:547 +#: apps/establishment/serializers/common.py:605 #: apps/timetable/serialziers.py:61 msgid "Establishment not found." msgstr "" -#: apps/establishment/serializers/common.py:586 -#: apps/establishment/serializers/common.py:614 apps/news/serializers.py:469 -#: apps/news/serializers.py:495 apps/product/serializers/common.py:183 +#: apps/establishment/serializers/common.py:644 +#: apps/establishment/serializers/common.py:672 apps/news/serializers.py:455 +#: apps/news/serializers.py:481 apps/product/serializers/common.py:183 msgid "Object not found." msgstr "" -#: apps/establishment/serializers/common.py:675 +#: apps/establishment/serializers/common.py:733 msgid "Fax is already reserved." msgstr "" -#: apps/establishment/serializers/common.py:679 +#: apps/establishment/serializers/common.py:737 msgid "Phones is already reserved." msgstr "" @@ -1132,8 +1139,8 @@ msgstr "" msgid "image orientation" msgstr "" -#: apps/gallery/models.py:35 apps/utils/models.py:169 apps/utils/models.py:198 -#: apps/utils/models.py:207 apps/utils/models.py:248 apps/utils/models.py:283 +#: apps/gallery/models.py:35 apps/utils/models.py:198 apps/utils/models.py:227 +#: apps/utils/models.py:236 apps/utils/models.py:277 apps/utils/models.py:312 msgid "Image" msgstr "" @@ -1633,11 +1640,11 @@ msgstr "" msgid "news galleries" msgstr "" -#: apps/news/serializers.py:276 apps/news/serializers.py:308 +#: apps/news/serializers.py:279 apps/news/serializers.py:311 msgid "Slug should be unique" msgstr "" -#: apps/news/serializers.py:443 +#: apps/news/serializers.py:429 msgid "News not found" msgstr "" @@ -1699,7 +1706,7 @@ msgstr "" #: apps/notification/tasks.py:31 msgid "You have subscribed on news G&M" -msgstr "" +msgstr "Vous êtes abonné aux actualités G&M" #: apps/notification/tasks.py:32 msgid "
" @@ -1707,48 +1714,52 @@ msgstr "" #: apps/notification/tasks.py:46 msgid "G&M Subscriptions" -msgstr "" +msgstr "Abonnements G&M" #: apps/notification/tasks.py:73 msgid "You have successfully unsubscribed from G&M news" -msgstr "" +msgstr "Vous avez réussi à vous désinscrire des actualités G&M" -#: apps/partner/apps.py:7 apps/partner/models.py:36 +#: apps/partner/apps.py:7 apps/partner/models.py:50 msgid "partner" msgstr "" -#: apps/partner/models.py:14 +#: apps/partner/models.py:29 msgid "Partner" msgstr "" -#: apps/partner/models.py:15 +#: apps/partner/models.py:30 msgid "Sponsor" msgstr "" -#: apps/partner/models.py:20 -msgid "Partner URL" -msgstr "" - -#: apps/partner/models.py:21 +#: apps/partner/models.py:36 apps/partner/models.py:65 msgid "Partner image URL" msgstr "" -#: apps/partner/models.py:31 +#: apps/partner/models.py:42 msgid "starting date" msgstr "" -#: apps/partner/models.py:32 +#: apps/partner/models.py:43 msgid "expiry date" msgstr "" -#: apps/partner/models.py:33 +#: apps/partner/models.py:44 msgid "price per month" msgstr "" -#: apps/partner/models.py:37 +#: apps/partner/models.py:51 msgid "partners" msgstr "" +#: apps/partner/models.py:63 +msgid "Date partner binded" +msgstr "" + +#: apps/partner/models.py:64 +msgid "Establishment to Partner URL" +msgstr "" + #: apps/product/apps.py:7 apps/product/models.py:323 msgid "Product" msgstr "" @@ -2374,43 +2385,47 @@ msgstr "" msgid "Advertorial already exists for this guide element." msgstr "" -#: apps/utils/models.py:29 +#: apps/utils/models.py:30 msgid "Date created" msgstr "" -#: apps/utils/models.py:31 +#: apps/utils/models.py:32 msgid "Date updated" msgstr "" -#: apps/utils/models.py:148 +#: apps/utils/models.py:150 msgid "created by" msgstr "" -#: apps/utils/models.py:152 +#: apps/utils/models.py:154 msgid "modified by" msgstr "" -#: apps/utils/models.py:258 +#: apps/utils/models.py:169 +msgid "File" +msgstr "" + +#: apps/utils/models.py:287 msgid "SVG image" msgstr "" -#: apps/utils/models.py:295 +#: apps/utils/models.py:324 msgid "Mobile" msgstr "" -#: apps/utils/models.py:296 +#: apps/utils/models.py:325 msgid "Web" msgstr "" -#: apps/utils/models.py:297 +#: apps/utils/models.py:326 msgid "All" msgstr "" -#: apps/utils/models.py:300 +#: apps/utils/models.py:329 msgid "Source" msgstr "" -#: apps/utils/models.py:427 +#: apps/utils/models.py:456 msgid "Is the main image" msgstr "" @@ -2475,16 +2490,16 @@ msgstr "" #: project/templates/notification/update_email.html:44 msgid "Follow us" -msgstr "" +msgstr "Signez maintenant" #: project/templates/notification/update_email.html:46 msgid "You can also us on our social network below" -msgstr "" +msgstr "Vous pouvez également nous sur notre réseau social ci-dessous" #: project/templates/notification/update_email.html:62 msgid "This email has been sent to" -msgstr "" +msgstr "Cet e-mail a été envoyé à" #: project/templates/notification/update_email.html:63 msgid "click here to unsubscribe" -msgstr "" +msgstr "cliquez ici pour vous désinscrire" diff --git a/project/locale/ru/LC_MESSAGES/django.mo b/project/locale/ru/LC_MESSAGES/django.mo index c90e51f2e2979e803403ecc8744353004e93545d..bf09c5e8e133770acb626ccb8f2e932e427fd8e0 100644 GIT binary patch delta 937 zcmY+A&ubGw6vroRtv^}?^`fZw4l0TVC0@jfpwQ?c7ZVUK!e*V2rQ6+-$r?Pxt)S5c zM2qKMy$ES(bZgq=9}syXp7oDV!Gnn3x0}#9%j2^%^L^j<-u#}nv#oDOrrs#5Lx_`z z4&o@{4?@Rw*muB-;9KxC_!Ybi{sfPMXD5`J2Cst$!8s7V zEma;}+y_5FtU)ozPi2kV0k2|T1&@KN;59G-UGN8(2k-7t>L&OCyaav*XTiVVDR2hW zCI12_!`=XMs+vuA00*e6_8}x`F9LaL5+O@EmNkPwy>t@UkCzy#xzP8+CPhXS&K0Q? zRg7Er78_m|m{-a9R=MUG(hH8~Q_V3{(K;Zbg9bH1buWy_bpmpH6T*PPfWoLwCUiZ= zr$9HFVSOGc@K3ch=b8tf{LBwg6a(&O8 zr<$&7^g_{&aP9lATz-`Yyum|GY#R~V4%wJ{ylJ0t*T#x>?qmMQ2^ESfUnWW|erK0> zAld=GHTxVn+njKZuvz9l?sy;)DEi#R9S%0QZ(k~YZI=mGUHHA1ge^GW2S?a!<9rjp zN&0JJ;`QvWEnTGr?Ne?gko9dxe6v$YPjeFS%8FpD@o=%|M*~U?@f`5F^p_?Uile@s zpy45!X^SA6VVFM8e+~uAM)t8h5k8qWdmAO*XkZJa(s4du=wAA)+4N&aJhh~(oS7{D E14vb8%m4rY delta 207 zcmcb}^MkGao)F7a1|VPuVi_O~0b*_-?g3&D*a5^K@tr`-3B=ccm<@;@05LBRKL=uv z_*WnXiT?-UGmJns5L*D*mzfwCB!DyzGY|u5RUj=3q>X?yP~4Is0Lb723SjtD8k_BzzA#QsX9=AAk2M$o{J<4N diff --git a/project/locale/ru/LC_MESSAGES/django.po b/project/locale/ru/LC_MESSAGES/django.po index 1b6ee13c..ed3b6069 100644 --- a/project/locale/ru/LC_MESSAGES/django.po +++ b/project/locale/ru/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-01-28 15:14+0000\n" +"POT-Creation-Date: 2020-01-30 01:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -36,7 +36,7 @@ msgstr "" msgid "Permissions" msgstr "" -#: apps/account/admin.py:61 apps/establishment/models.py:1101 +#: apps/account/admin.py:61 apps/establishment/models.py:1103 #: apps/location/models.py:41 apps/product/models.py:49 #: apps/product/models.py:87 msgid "Name" @@ -62,181 +62,180 @@ msgstr "" msgid "New password confirmation" msgstr "" -#: apps/account/models.py:56 +#: apps/account/models.py:57 msgid "Standard user" msgstr "" -#: apps/account/models.py:57 +#: apps/account/models.py:58 msgid "Comments moderator" msgstr "" -#: apps/account/models.py:58 +#: apps/account/models.py:59 msgid "Country admin" msgstr "" -#: apps/account/models.py:59 +#: apps/account/models.py:60 msgid "Content page manager" msgstr "" -#: apps/account/models.py:60 +#: apps/account/models.py:61 msgid "Establishment manager" msgstr "" -#: apps/account/models.py:61 +#: apps/account/models.py:62 msgid "Reviewer manager" msgstr "" -#: apps/account/models.py:62 +#: apps/account/models.py:63 msgid "Restaurant reviewer" msgstr "" -#: apps/account/models.py:63 +#: apps/account/models.py:64 msgid "Sales man" msgstr "" -#: apps/account/models.py:64 +#: apps/account/models.py:65 msgid "Winery reviewer" msgstr "" -#: apps/account/models.py:65 +#: apps/account/models.py:66 msgid "Seller" msgstr "" -#: apps/account/models.py:66 +#: apps/account/models.py:67 msgid "Liquor reviewer" msgstr "" -#: apps/account/models.py:67 +#: apps/account/models.py:68 msgid "Product reviewer" msgstr "" -#: apps/account/models.py:70 apps/account/models.py:501 +#: apps/account/models.py:71 apps/account/models.py:511 msgid "Role" msgstr "" -#: apps/account/models.py:72 apps/establishment/models.py:1420 +#: apps/account/models.py:73 apps/establishment/models.py:1425 #: apps/location/models.py:57 apps/main/models.py:61 apps/review/models.py:57 msgid "Country" msgstr "" -#: apps/account/models.py:74 apps/main/models.py:88 +#: apps/account/models.py:75 apps/main/models.py:88 msgid "Site settings" msgstr "" -#: apps/account/models.py:77 apps/establishment/models.py:112 +#: apps/account/models.py:78 apps/establishment/models.py:111 msgid "Establishment subtype" msgstr "" -#: apps/account/models.py:83 +#: apps/account/models.py:84 msgid "navigation bar permission" msgstr "" -#: apps/account/models.py:207 +#: apps/account/models.py:208 msgid "username" msgstr "" -#: apps/account/models.py:210 +#: apps/account/models.py:211 msgid "Required. 150 characters or fewer. Letters, digits and ./+/-/_ only." msgstr "" -#: apps/account/models.py:212 +#: apps/account/models.py:213 msgid "A user with that username already exists." msgstr "" -#: apps/account/models.py:215 apps/news/models.py:49 apps/utils/models.py:270 +#: apps/account/models.py:216 apps/news/models.py:49 apps/utils/models.py:299 msgid "Image URL path" msgstr "" -#: apps/account/models.py:218 +#: apps/account/models.py:219 msgid "Cropped image URL path" msgstr "" -#: apps/account/models.py:220 +#: apps/account/models.py:221 msgid "email address" msgstr "" -#: apps/account/models.py:222 +#: apps/account/models.py:223 msgid "unconfirmed email" msgstr "" -#: apps/account/models.py:223 +#: apps/account/models.py:224 msgid "email status" msgstr "" -#: apps/account/models.py:227 +#: apps/account/models.py:228 msgid "User last used locale" msgstr "" -#: apps/account/models.py:229 +#: apps/account/models.py:230 msgid "User last visited from city" msgstr "" -#: apps/account/models.py:230 +#: apps/account/models.py:231 msgid "last IP address" msgstr "" -#: apps/account/models.py:233 +#: apps/account/models.py:234 msgid "last site settings" msgstr "" -#: apps/account/models.py:240 +#: apps/account/models.py:241 msgid "Phone" msgstr "" -#: apps/account/models.py:247 +#: apps/account/models.py:248 msgid "Roles" msgstr "" -#: apps/account/models.py:253 apps/account/models.py:499 -#: apps/comment/models.py:74 apps/establishment/models.py:1100 +#: apps/account/models.py:254 apps/account/models.py:509 +#: apps/comment/models.py:74 apps/establishment/models.py:1102 #: apps/favorites/models.py:23 apps/notification/models.py:104 msgid "User" msgstr "" -#: apps/account/models.py:254 +#: apps/account/models.py:255 msgid "Users" msgstr "" -#: apps/account/models.py:492 +#: apps/account/models.py:502 msgid "validated" msgstr "" -#: apps/account/models.py:493 +#: apps/account/models.py:503 msgid "pending" msgstr "" -#: apps/account/models.py:494 +#: apps/account/models.py:504 msgid "cancelled" msgstr "" -#: apps/account/models.py:495 +#: apps/account/models.py:505 msgid "rejected" msgstr "" -#: apps/account/models.py:503 apps/establishment/apps.py:8 -#: apps/establishment/models.py:614 apps/establishment/models.py:975 -#: apps/partner/models.py:24 +#: apps/account/models.py:513 apps/establishment/apps.py:8 +#: apps/establishment/models.py:613 apps/establishment/models.py:977 msgid "Establishment" msgstr "" -#: apps/account/models.py:507 apps/collection/models.py:280 +#: apps/account/models.py:517 apps/collection/models.py:317 #: apps/product/models.py:293 msgid "state" msgstr "" -#: apps/account/models.py:521 +#: apps/account/models.py:531 msgid "New role" msgstr "" -#: apps/account/models.py:522 +#: apps/account/models.py:532 msgid "Old role" msgstr "" -#: apps/account/serializers/common.py:226 +#: apps/account/serializers/common.py:230 msgid "Old password mismatch." msgstr "" -#: apps/account/serializers/common.py:229 apps/utils/exceptions.py:103 +#: apps/account/serializers/common.py:233 apps/utils/exceptions.py:103 msgid "Password is already in use" msgstr "" @@ -244,13 +243,13 @@ msgstr "" msgid "advertisement" msgstr "" -#: apps/advertisement/models.py:43 apps/collection/models.py:748 -#: apps/collection/models.py:968 apps/establishment/models.py:527 -#: apps/establishment/models.py:1288 apps/establishment/models.py:1353 +#: apps/advertisement/models.py:43 apps/collection/models.py:785 +#: apps/collection/models.py:1005 apps/establishment/models.py:526 +#: apps/establishment/models.py:1321 apps/establishment/models.py:1358 #: apps/location/models.py:286 apps/location/models.py:317 #: apps/location/models.py:344 apps/main/models.py:258 apps/main/models.py:443 #: apps/news/models.py:283 apps/notification/models.py:118 -#: apps/partner/models.py:18 apps/product/models.py:289 +#: apps/partner/models.py:33 apps/product/models.py:289 #: apps/product/models.py:526 apps/product/models.py:592 #: apps/recipe/models.py:61 apps/review/models.py:90 apps/review/models.py:130 #: apps/review/models.py:158 apps/review/models.py:175 apps/tag/models.py:45 @@ -266,7 +265,7 @@ msgid "Block level" msgstr "" #: apps/advertisement/models.py:48 apps/collection/models.py:39 -#: apps/collection/models.py:269 +#: apps/collection/models.py:306 msgid "start" msgstr "" @@ -385,13 +384,14 @@ msgid "collection" msgstr "" #: apps/collection/models.py:29 apps/collection/models.py:78 -#: apps/collection/models.py:690 apps/establishment/models.py:528 -#: apps/establishment/models.py:1214 apps/establishment/models.py:1450 -#: apps/location/models.py:101 apps/location/models.py:280 -#: apps/location/models.py:313 apps/location/models.py:341 -#: apps/main/models.py:32 apps/main/models.py:223 apps/main/models.py:386 -#: apps/main/models.py:428 apps/news/models.py:64 -#: apps/notification/models.py:20 apps/partner/models.py:19 +#: apps/collection/models.py:727 apps/establishment/models.py:527 +#: apps/establishment/models.py:1216 apps/establishment/models.py:1251 +#: apps/establishment/models.py:1296 apps/establishment/models.py:1338 +#: apps/establishment/models.py:1455 apps/location/models.py:101 +#: apps/location/models.py:280 apps/location/models.py:313 +#: apps/location/models.py:341 apps/main/models.py:32 apps/main/models.py:223 +#: apps/main/models.py:386 apps/main/models.py:428 apps/news/models.py:64 +#: apps/notification/models.py:20 apps/partner/models.py:34 #: apps/product/models.py:260 apps/product/models.py:490 #: apps/product/models.py:521 apps/review/models.py:161 msgid "name" @@ -410,7 +410,7 @@ msgid "Collection type" msgstr "" #: apps/collection/models.py:84 apps/comment/models.py:76 -#: apps/establishment/models.py:574 +#: apps/establishment/models.py:573 msgid "Publish status" msgstr "" @@ -429,8 +429,8 @@ msgstr "" msgid "collection block properties" msgstr "" -#: apps/collection/models.py:93 apps/establishment/models.py:535 -#: apps/establishment/models.py:1217 apps/location/models.py:289 +#: apps/collection/models.py:93 apps/establishment/models.py:534 +#: apps/establishment/models.py:1219 apps/location/models.py:289 #: apps/main/models.py:434 apps/news/models.py:295 apps/product/models.py:261 #: apps/review/models.py:163 msgid "description" @@ -444,165 +444,165 @@ msgstr "" msgid "collections" msgstr "" -#: apps/collection/models.py:260 +#: apps/collection/models.py:297 msgid "Restaurant" msgstr "" -#: apps/collection/models.py:261 +#: apps/collection/models.py:298 msgid "Artisan" msgstr "" -#: apps/collection/models.py:262 +#: apps/collection/models.py:299 msgid "Wine" msgstr "" -#: apps/collection/models.py:267 +#: apps/collection/models.py:304 msgid "guide type" msgstr "" -#: apps/collection/models.py:273 +#: apps/collection/models.py:310 msgid "guide vintage year" msgstr "" -#: apps/collection/models.py:275 +#: apps/collection/models.py:312 msgid "slug" msgstr "" -#: apps/collection/models.py:278 apps/news/models.py:336 +#: apps/collection/models.py:315 apps/news/models.py:336 msgid "site settings" msgstr "" -#: apps/collection/models.py:283 +#: apps/collection/models.py:320 msgid "* after rebuild guide, refresh count of related guide elements" msgstr "" -#: apps/collection/models.py:284 +#: apps/collection/models.py:321 msgid "count of related guide elements during initialization" msgstr "" -#: apps/collection/models.py:291 apps/collection/models.py:463 +#: apps/collection/models.py:328 apps/collection/models.py:500 msgid "guide" msgstr "" -#: apps/collection/models.py:292 +#: apps/collection/models.py:329 msgid "guides" msgstr "" -#: apps/collection/models.py:413 +#: apps/collection/models.py:450 msgid "number of pages" msgstr "" -#: apps/collection/models.py:414 +#: apps/collection/models.py:451 msgid "the total number of reserved pages" msgstr "" -#: apps/collection/models.py:416 +#: apps/collection/models.py:453 msgid "number of right pages" msgstr "" -#: apps/collection/models.py:417 +#: apps/collection/models.py:454 msgid "the number of right pages (which are part of total number)." msgstr "" -#: apps/collection/models.py:420 apps/collection/models.py:974 +#: apps/collection/models.py:457 apps/collection/models.py:1011 msgid "guide element" msgstr "" -#: apps/collection/models.py:427 +#: apps/collection/models.py:464 msgid "advertorial" msgstr "" -#: apps/collection/models.py:428 +#: apps/collection/models.py:465 msgid "advertorials" msgstr "" -#: apps/collection/models.py:449 +#: apps/collection/models.py:486 msgid "with mark" msgstr "" -#: apps/collection/models.py:450 +#: apps/collection/models.py:487 msgid "exclude empty marks?" msgstr "" -#: apps/collection/models.py:453 +#: apps/collection/models.py:490 msgid "max mark" msgstr "" -#: apps/collection/models.py:455 +#: apps/collection/models.py:492 msgid "mark under" msgstr "" -#: apps/collection/models.py:456 +#: apps/collection/models.py:493 msgid "min mark" msgstr "" -#: apps/collection/models.py:458 +#: apps/collection/models.py:495 msgid "mark over" msgstr "" -#: apps/collection/models.py:470 +#: apps/collection/models.py:507 msgid "guide filter" msgstr "" -#: apps/collection/models.py:471 +#: apps/collection/models.py:508 msgid "guide filters" msgstr "" -#: apps/collection/models.py:694 apps/collection/models.py:943 +#: apps/collection/models.py:731 apps/collection/models.py:980 msgid "guide element type" msgstr "" -#: apps/collection/models.py:695 +#: apps/collection/models.py:732 msgid "guide element types" msgstr "" -#: apps/collection/models.py:709 apps/collection/models.py:744 +#: apps/collection/models.py:746 apps/collection/models.py:781 msgid "section name" msgstr "" -#: apps/collection/models.py:715 +#: apps/collection/models.py:752 msgid "guide wine color section" msgstr "" -#: apps/collection/models.py:716 +#: apps/collection/models.py:753 msgid "guide wine color sections" msgstr "" -#: apps/collection/models.py:727 +#: apps/collection/models.py:764 msgid "category name" msgstr "" -#: apps/collection/models.py:733 +#: apps/collection/models.py:770 msgid "guide element section category" msgstr "" -#: apps/collection/models.py:734 +#: apps/collection/models.py:771 msgid "guide element section categories" msgstr "" -#: apps/collection/models.py:746 apps/establishment/admin.py:121 -#: apps/establishment/models.py:1276 +#: apps/collection/models.py:783 apps/establishment/admin.py:121 +#: apps/establishment/models.py:1253 apps/establishment/models.py:1318 msgid "category" msgstr "" -#: apps/collection/models.py:754 +#: apps/collection/models.py:791 msgid "guide element section" msgstr "" -#: apps/collection/models.py:755 +#: apps/collection/models.py:792 msgid "guide element sections" msgstr "" -#: apps/collection/models.py:966 +#: apps/collection/models.py:1003 msgid "label photo" msgstr "" -#: apps/collection/models.py:975 +#: apps/collection/models.py:1012 msgid "guide elements" msgstr "" -#: apps/collection/views/back.py:177 apps/collection/views/back.py:193 -#: apps/collection/views/back.py:209 apps/main/views/back.py:174 +#: apps/collection/views/back.py:168 apps/collection/views/back.py:184 +#: apps/collection/views/back.py:200 apps/main/views/back.py:174 #: apps/main/views/back.py:190 msgid "The file will be sent to your email." msgstr "" @@ -661,451 +661,458 @@ msgstr "" msgid "default language" msgstr "" -#: apps/establishment/filters.py:126 apps/news/filters.py:55 +#: apps/establishment/filters.py:125 apps/news/filters.py:55 msgid "Type at least 3 characters to search please." msgstr "" -#: apps/establishment/models.py:50 apps/establishment/models.py:91 -#: apps/establishment/models.py:935 apps/recipe/models.py:53 +#: apps/establishment/models.py:49 apps/establishment/models.py:90 +#: apps/establishment/models.py:937 apps/recipe/models.py:53 msgid "Description" msgstr "" -#: apps/establishment/models.py:53 apps/establishment/models.py:94 -#: apps/establishment/models.py:533 apps/establishment/models.py:941 +#: apps/establishment/models.py:52 apps/establishment/models.py:93 +#: apps/establishment/models.py:532 apps/establishment/models.py:943 #: apps/notification/models.py:18 apps/product/models.py:51 #: apps/product/models.py:89 msgid "Index name" msgstr "" -#: apps/establishment/models.py:54 apps/product/models.py:52 +#: apps/establishment/models.py:53 apps/product/models.py:52 msgid "Use subtypes" msgstr "" -#: apps/establishment/models.py:58 apps/establishment/models.py:101 +#: apps/establishment/models.py:57 apps/establishment/models.py:100 #: apps/product/models.py:56 apps/tag/models.py:176 msgid "Tag categories" msgstr "" -#: apps/establishment/models.py:67 +#: apps/establishment/models.py:66 msgid "Establishment type" msgstr "" -#: apps/establishment/models.py:68 +#: apps/establishment/models.py:67 msgid "Establishment types" msgstr "" -#: apps/establishment/models.py:97 apps/product/models.py:266 +#: apps/establishment/models.py:96 apps/product/models.py:266 msgid "Type" msgstr "" -#: apps/establishment/models.py:113 +#: apps/establishment/models.py:112 msgid "Establishment subtypes" msgstr "" -#: apps/establishment/models.py:117 +#: apps/establishment/models.py:116 msgid "Establishment type is not use subtypes." msgstr "" -#: apps/establishment/models.py:530 +#: apps/establishment/models.py:529 msgid "Transliterated name" msgstr "" -#: apps/establishment/models.py:532 +#: apps/establishment/models.py:531 msgid "Western name" msgstr "" -#: apps/establishment/models.py:539 apps/product/models.py:275 +#: apps/establishment/models.py:538 apps/product/models.py:275 msgid "public mark" msgstr "" -#: apps/establishment/models.py:543 +#: apps/establishment/models.py:542 msgid "toque number" msgstr "" -#: apps/establishment/models.py:547 +#: apps/establishment/models.py:546 apps/establishment/models.py:1339 msgid "type" msgstr "" -#: apps/establishment/models.py:551 +#: apps/establishment/models.py:550 msgid "subtype" msgstr "" -#: apps/establishment/models.py:554 apps/establishment/models.py:1473 +#: apps/establishment/models.py:553 apps/establishment/models.py:1478 #: apps/news/models.py:34 apps/news/models.py:315 msgid "address" msgstr "" -#: apps/establishment/models.py:557 +#: apps/establishment/models.py:556 msgid "price level" msgstr "" -#: apps/establishment/models.py:559 +#: apps/establishment/models.py:558 msgid "Web site URL" msgstr "" -#: apps/establishment/models.py:561 +#: apps/establishment/models.py:560 msgid "Facebook URL" msgstr "" -#: apps/establishment/models.py:563 +#: apps/establishment/models.py:562 msgid "Twitter URL" msgstr "" -#: apps/establishment/models.py:565 +#: apps/establishment/models.py:564 msgid "Instagram URL" msgstr "" -#: apps/establishment/models.py:567 +#: apps/establishment/models.py:566 msgid "Lafourchette URL" msgstr "" -#: apps/establishment/models.py:568 +#: apps/establishment/models.py:567 msgid "guestonline id" msgstr "" -#: apps/establishment/models.py:570 +#: apps/establishment/models.py:569 msgid "lastable id" msgstr "" -#: apps/establishment/models.py:573 +#: apps/establishment/models.py:572 msgid "Booking URL" msgstr "" -#: apps/establishment/models.py:576 apps/establishment/models.py:1285 +#: apps/establishment/models.py:575 msgid "Establishment schedule" msgstr "" -#: apps/establishment/models.py:579 +#: apps/establishment/models.py:578 msgid "Transportation" msgstr "" -#: apps/establishment/models.py:583 +#: apps/establishment/models.py:582 msgid "Collections" msgstr "" -#: apps/establishment/models.py:585 +#: apps/establishment/models.py:584 msgid "Preview image URL path" msgstr "" -#: apps/establishment/models.py:588 +#: apps/establishment/models.py:587 msgid "Establishment slug" msgstr "" -#: apps/establishment/models.py:593 apps/product/models.py:296 +#: apps/establishment/models.py:592 apps/product/models.py:296 #: apps/product/models.py:591 apps/tag/models.py:65 msgid "Tag" msgstr "" -#: apps/establishment/models.py:600 apps/establishment/models.py:1223 +#: apps/establishment/models.py:599 apps/establishment/models.py:1225 #: apps/main/models.py:39 msgid "currency" msgstr "" -#: apps/establishment/models.py:604 apps/product/models.py:483 +#: apps/establishment/models.py:603 apps/product/models.py:483 msgid "purchased plaques" msgstr "" -#: apps/establishment/models.py:605 +#: apps/establishment/models.py:604 msgid "" "Attribute from legacy db.\n" "Must be deleted after the implementation of the market." msgstr "" -#: apps/establishment/models.py:615 +#: apps/establishment/models.py:614 apps/partner/models.py:40 msgid "Establishments" msgstr "" -#: apps/establishment/models.py:896 apps/product/models.py:609 +#: apps/establishment/models.py:898 apps/product/models.py:609 #: apps/review/models.py:69 msgid "text" msgstr "" -#: apps/establishment/models.py:899 apps/establishment/models.py:917 -#: apps/establishment/models.py:1279 apps/establishment/models.py:1356 -#: apps/establishment/models.py:1449 apps/product/models.py:273 +#: apps/establishment/models.py:901 apps/establishment/models.py:919 +#: apps/establishment/models.py:1298 apps/establishment/models.py:1361 +#: apps/establishment/models.py:1454 apps/product/models.py:273 #: apps/product/models.py:472 msgid "establishment" msgstr "" -#: apps/establishment/models.py:903 apps/product/models.py:616 +#: apps/establishment/models.py:905 apps/product/models.py:616 #: apps/review/models.py:103 apps/review/models.py:138 msgid "author" msgstr "" -#: apps/establishment/models.py:909 +#: apps/establishment/models.py:911 msgid "establishment notes" msgstr "" -#: apps/establishment/models.py:910 +#: apps/establishment/models.py:912 msgid "establishment note" msgstr "" -#: apps/establishment/models.py:921 apps/establishment/models.py:1311 -#: apps/product/models.py:545 apps/review/models.py:188 +#: apps/establishment/models.py:923 apps/product/models.py:545 +#: apps/review/models.py:188 msgid "image" msgstr "" -#: apps/establishment/models.py:925 +#: apps/establishment/models.py:927 msgid "establishment gallery" msgstr "" -#: apps/establishment/models.py:926 +#: apps/establishment/models.py:928 msgid "establishment galleries" msgstr "" -#: apps/establishment/models.py:946 apps/establishment/models.py:983 +#: apps/establishment/models.py:948 apps/establishment/models.py:985 msgid "Position" msgstr "" -#: apps/establishment/models.py:947 +#: apps/establishment/models.py:949 msgid "Positions" msgstr "" -#: apps/establishment/models.py:977 apps/establishment/models.py:1140 +#: apps/establishment/models.py:979 apps/establishment/models.py:1142 msgid "Employee" msgstr "" -#: apps/establishment/models.py:978 +#: apps/establishment/models.py:980 msgid "From date" msgstr "" -#: apps/establishment/models.py:981 +#: apps/establishment/models.py:983 msgid "To date" msgstr "" -#: apps/establishment/models.py:988 apps/establishment/models.py:1128 +#: apps/establishment/models.py:990 apps/establishment/models.py:1130 msgid "Old id" msgstr "" -#: apps/establishment/models.py:1102 +#: apps/establishment/models.py:1104 msgid "Last Name" msgstr "" -#: apps/establishment/models.py:1110 +#: apps/establishment/models.py:1112 msgid "Male" msgstr "" -#: apps/establishment/models.py:1111 +#: apps/establishment/models.py:1113 msgid "Female" msgstr "" -#: apps/establishment/models.py:1113 +#: apps/establishment/models.py:1115 msgid "Sex" msgstr "" -#: apps/establishment/models.py:1115 +#: apps/establishment/models.py:1117 msgid "Birth date" msgstr "" -#: apps/establishment/models.py:1117 apps/notification/models.py:106 +#: apps/establishment/models.py:1119 apps/notification/models.py:106 msgid "Email" msgstr "" -#: apps/establishment/models.py:1119 +#: apps/establishment/models.py:1121 msgid "Toque number" msgstr "" -#: apps/establishment/models.py:1126 apps/news/models.py:321 +#: apps/establishment/models.py:1128 apps/news/models.py:321 #: apps/tag/models.py:66 msgid "Tags" msgstr "" -#: apps/establishment/models.py:1129 +#: apps/establishment/models.py:1131 msgid "Available for events" msgstr "" -#: apps/establishment/models.py:1133 apps/location/models.py:170 +#: apps/establishment/models.py:1135 apps/location/models.py:170 msgid "image instance of model Image" msgstr "" -#: apps/establishment/models.py:1141 +#: apps/establishment/models.py:1143 msgid "Employees" msgstr "" -#: apps/establishment/models.py:1188 +#: apps/establishment/models.py:1190 msgid "contact phone" msgstr "" -#: apps/establishment/models.py:1189 apps/establishment/models.py:1453 +#: apps/establishment/models.py:1191 apps/establishment/models.py:1458 msgid "contact phones" msgstr "" -#: apps/establishment/models.py:1202 +#: apps/establishment/models.py:1204 msgid "contact email" msgstr "" -#: apps/establishment/models.py:1203 +#: apps/establishment/models.py:1205 msgid "contact emails" msgstr "" -#: apps/establishment/models.py:1220 apps/review/models.py:141 +#: apps/establishment/models.py:1222 apps/establishment/models.py:1255 +#: apps/establishment/models.py:1301 apps/review/models.py:141 msgid "price" msgstr "" -#: apps/establishment/models.py:1221 +#: apps/establishment/models.py:1223 msgid "is signature plate" msgstr "" -#: apps/establishment/models.py:1226 +#: apps/establishment/models.py:1228 msgid "currency code" msgstr "" -#: apps/establishment/models.py:1230 apps/establishment/models.py:1293 -#: apps/establishment/models.py:1294 apps/establishment/models.py:1304 -#: apps/establishment/models.py:1326 +#: apps/establishment/models.py:1232 apps/establishment/models.py:1326 +#: apps/establishment/models.py:1327 msgid "menu" msgstr "" -#: apps/establishment/models.py:1240 +#: apps/establishment/models.py:1242 msgid "plate" msgstr "" -#: apps/establishment/models.py:1241 +#: apps/establishment/models.py:1243 msgid "plates" msgstr "" -#: apps/establishment/models.py:1281 +#: apps/establishment/models.py:1256 +msgid "signature" +msgstr "" + +#: apps/establishment/models.py:1259 +msgid "dish" +msgstr "" + +#: apps/establishment/models.py:1260 +msgid "dishes" +msgstr "" + +#: apps/establishment/models.py:1300 msgid "is drinks included" msgstr "" -#: apps/establishment/models.py:1316 -msgid "menu gallery" +#: apps/establishment/models.py:1305 +msgid "Menu schedule" msgstr "" -#: apps/establishment/models.py:1317 -msgid "menu galleries" +#: apps/establishment/models.py:1310 +msgid "Menu files" msgstr "" -#: apps/establishment/models.py:1330 apps/establishment/models.py:1342 -#: apps/gallery/models.py:29 apps/main/models.py:196 apps/main/models.py:402 -#: apps/news/models.py:47 apps/news/models.py:287 -msgid "title" +#: apps/establishment/models.py:1315 +msgid "Menu dishes" msgstr "" -#: apps/establishment/models.py:1332 -msgid "File" -msgstr "" - -#: apps/establishment/models.py:1337 +#: apps/establishment/models.py:1342 msgid "menu upload" msgstr "" -#: apps/establishment/models.py:1338 +#: apps/establishment/models.py:1343 msgid "menu uploads" msgstr "" -#: apps/establishment/models.py:1345 +#: apps/establishment/models.py:1347 apps/gallery/models.py:29 +#: apps/main/models.py:196 apps/main/models.py:402 apps/news/models.py:47 +#: apps/news/models.py:287 +msgid "title" +msgstr "" + +#: apps/establishment/models.py:1350 msgid "social choice" msgstr "" -#: apps/establishment/models.py:1346 +#: apps/establishment/models.py:1351 msgid "social choices" msgstr "" -#: apps/establishment/models.py:1362 apps/establishment/models.py:1369 +#: apps/establishment/models.py:1367 apps/establishment/models.py:1374 msgid "social network" msgstr "" -#: apps/establishment/models.py:1366 +#: apps/establishment/models.py:1371 msgid "URL" msgstr "" -#: apps/establishment/models.py:1370 +#: apps/establishment/models.py:1375 msgid "social networks" msgstr "" -#: apps/establishment/models.py:1411 +#: apps/establishment/models.py:1416 msgid "One" msgstr "" -#: apps/establishment/models.py:1412 +#: apps/establishment/models.py:1417 msgid "Two" msgstr "" -#: apps/establishment/models.py:1413 +#: apps/establishment/models.py:1418 msgid "Three" msgstr "" -#: apps/establishment/models.py:1414 +#: apps/establishment/models.py:1419 msgid "Four" msgstr "" -#: apps/establishment/models.py:1415 +#: apps/establishment/models.py:1420 msgid "Five" msgstr "" -#: apps/establishment/models.py:1430 apps/establishment/models.py:1431 +#: apps/establishment/models.py:1435 apps/establishment/models.py:1436 msgid "Rating strategy" msgstr "" -#: apps/establishment/models.py:1456 +#: apps/establishment/models.py:1461 msgid "fax numbers" msgstr "" -#: apps/establishment/models.py:1459 +#: apps/establishment/models.py:1464 msgid "legal entity" msgstr "" -#: apps/establishment/models.py:1462 +#: apps/establishment/models.py:1467 msgid "registry number" msgstr "" -#: apps/establishment/models.py:1465 +#: apps/establishment/models.py:1470 msgid "VAT identification number" msgstr "" -#: apps/establishment/models.py:1469 +#: apps/establishment/models.py:1474 msgid "sic code" msgstr "" -#: apps/establishment/models.py:1479 +#: apps/establishment/models.py:1484 msgid "company" msgstr "" -#: apps/establishment/models.py:1480 +#: apps/establishment/models.py:1485 msgid "companies" msgstr "" -#: apps/establishment/serializers/back.py:467 +#: apps/establishment/serializers/back.py:473 msgid "Establishment not found" msgstr "" -#: apps/establishment/serializers/back.py:470 -#: apps/establishment/serializers/back.py:680 apps/news/serializers.py:445 +#: apps/establishment/serializers/back.py:476 apps/news/serializers.py:431 #: apps/product/serializers/back.py:42 msgid "Image not found" msgstr "" -#: apps/establishment/serializers/back.py:476 +#: apps/establishment/serializers/back.py:482 #: apps/product/serializers/back.py:48 msgid "Image is already added." msgstr "" -#: apps/establishment/serializers/back.py:678 -msgid "Menu not found" -msgstr "" - -#: apps/establishment/serializers/common.py:212 +#: apps/establishment/serializers/common.py:270 #, python-brace-format msgid "{entity_class.__name__} not found." msgstr "" -#: apps/establishment/serializers/common.py:547 +#: apps/establishment/serializers/common.py:605 #: apps/timetable/serialziers.py:61 msgid "Establishment not found." msgstr "" -#: apps/establishment/serializers/common.py:586 -#: apps/establishment/serializers/common.py:614 apps/news/serializers.py:469 -#: apps/news/serializers.py:495 apps/product/serializers/common.py:183 +#: apps/establishment/serializers/common.py:644 +#: apps/establishment/serializers/common.py:672 apps/news/serializers.py:455 +#: apps/news/serializers.py:481 apps/product/serializers/common.py:183 msgid "Object not found." msgstr "" -#: apps/establishment/serializers/common.py:675 +#: apps/establishment/serializers/common.py:733 msgid "Fax is already reserved." msgstr "" -#: apps/establishment/serializers/common.py:679 +#: apps/establishment/serializers/common.py:737 msgid "Phones is already reserved." msgstr "" @@ -1134,8 +1141,8 @@ msgstr "" msgid "image orientation" msgstr "" -#: apps/gallery/models.py:35 apps/utils/models.py:169 apps/utils/models.py:198 -#: apps/utils/models.py:207 apps/utils/models.py:248 apps/utils/models.py:283 +#: apps/gallery/models.py:35 apps/utils/models.py:198 apps/utils/models.py:227 +#: apps/utils/models.py:236 apps/utils/models.py:277 apps/utils/models.py:312 msgid "Image" msgstr "" @@ -1635,11 +1642,11 @@ msgstr "" msgid "news galleries" msgstr "" -#: apps/news/serializers.py:276 apps/news/serializers.py:308 +#: apps/news/serializers.py:279 apps/news/serializers.py:311 msgid "Slug should be unique" msgstr "" -#: apps/news/serializers.py:443 +#: apps/news/serializers.py:429 msgid "News not found" msgstr "" @@ -1701,7 +1708,7 @@ msgstr "" #: apps/notification/tasks.py:31 msgid "You have subscribed on news G&M" -msgstr "" +msgstr "Вы подписались на новости GM" #: apps/notification/tasks.py:32 msgid "
" @@ -1709,48 +1716,52 @@ msgstr "" #: apps/notification/tasks.py:46 msgid "G&M Subscriptions" -msgstr "" +msgstr "Подписки GM" #: apps/notification/tasks.py:73 msgid "You have successfully unsubscribed from G&M news" -msgstr "" +msgstr "Вы успешно отпписались от рассылки GM" -#: apps/partner/apps.py:7 apps/partner/models.py:36 +#: apps/partner/apps.py:7 apps/partner/models.py:50 msgid "partner" msgstr "" -#: apps/partner/models.py:14 +#: apps/partner/models.py:29 msgid "Partner" msgstr "" -#: apps/partner/models.py:15 +#: apps/partner/models.py:30 msgid "Sponsor" msgstr "" -#: apps/partner/models.py:20 -msgid "Partner URL" -msgstr "" - -#: apps/partner/models.py:21 +#: apps/partner/models.py:36 apps/partner/models.py:65 msgid "Partner image URL" msgstr "" -#: apps/partner/models.py:31 +#: apps/partner/models.py:42 msgid "starting date" msgstr "" -#: apps/partner/models.py:32 +#: apps/partner/models.py:43 msgid "expiry date" msgstr "" -#: apps/partner/models.py:33 +#: apps/partner/models.py:44 msgid "price per month" msgstr "" -#: apps/partner/models.py:37 +#: apps/partner/models.py:51 msgid "partners" msgstr "" +#: apps/partner/models.py:63 +msgid "Date partner binded" +msgstr "" + +#: apps/partner/models.py:64 +msgid "Establishment to Partner URL" +msgstr "" + #: apps/product/apps.py:7 apps/product/models.py:323 msgid "Product" msgstr "" @@ -2376,43 +2387,47 @@ msgstr "" msgid "Advertorial already exists for this guide element." msgstr "" -#: apps/utils/models.py:29 +#: apps/utils/models.py:30 msgid "Date created" msgstr "" -#: apps/utils/models.py:31 +#: apps/utils/models.py:32 msgid "Date updated" msgstr "" -#: apps/utils/models.py:148 +#: apps/utils/models.py:150 msgid "created by" msgstr "" -#: apps/utils/models.py:152 +#: apps/utils/models.py:154 msgid "modified by" msgstr "" -#: apps/utils/models.py:258 +#: apps/utils/models.py:169 +msgid "File" +msgstr "" + +#: apps/utils/models.py:287 msgid "SVG image" msgstr "" -#: apps/utils/models.py:295 +#: apps/utils/models.py:324 msgid "Mobile" msgstr "" -#: apps/utils/models.py:296 +#: apps/utils/models.py:325 msgid "Web" msgstr "" -#: apps/utils/models.py:297 +#: apps/utils/models.py:326 msgid "All" msgstr "" -#: apps/utils/models.py:300 +#: apps/utils/models.py:329 msgid "Source" msgstr "" -#: apps/utils/models.py:427 +#: apps/utils/models.py:456 msgid "Is the main image" msgstr "" @@ -2477,16 +2492,16 @@ msgstr "" #: project/templates/notification/update_email.html:44 msgid "Follow us" -msgstr "" +msgstr "Подпишись сейчас" #: project/templates/notification/update_email.html:46 msgid "You can also us on our social network below" -msgstr "" +msgstr "Вы также можете найти нас в нашей социальной сети ниже" #: project/templates/notification/update_email.html:62 msgid "This email has been sent to" -msgstr "" +msgstr "Это сообщение было отослано для" #: project/templates/notification/update_email.html:63 msgid "click here to unsubscribe" -msgstr "" +msgstr "нажмите здесь для отписки"