Merge branch 'develop' into feature/fix-country-region-city-transfer

This commit is contained in:
littlewolf 2019-12-16 20:36:31 +03:00
commit 181e9599e4
19 changed files with 390 additions and 85 deletions

View File

@ -0,0 +1,49 @@
from django.core.management.base import BaseCommand
from tqdm import tqdm
from account.models import User, UserRole, Role
from transfer.models import OwnershipAffs
from establishment.models import Establishment
class Command(BaseCommand):
help = """Add ownership to UserRoles."""
def handle(self, *args, **kwarg):
create_user_roles = []
# filter owner records with state not null only
owners = OwnershipAffs.objects.filter(state__isnull=False)
# Get role, may be more then 1
role = Role.objects.filter(role=Role.ESTABLISHMENT_MANAGER).first()
if not role:
role = Role.objects.create(
role=Role.ESTABLISHMENT_MANAGER
)
for owner in tqdm(owners):
user = User.objects.filter(
old_id=owner.account_id).first()
requester = User.objects.filter(
old_id=owner.requester_id).first()
establishment = Establishment.objects.filter(
old_id=owner.establishment_id).first()
if user and establishment:
user_role = UserRole.objects.filter(
user=user, role=role, establishment=establishment, state=owner.state).first()
if not user_role:
# add to bulk_create
create_user_roles.append(UserRole(
user=user,
role=role,
establishment=establishment,
state=owner.state,
requester=requester
))
UserRole.objects.bulk_create(create_user_roles)
self.stdout.write(
self.style.WARNING(
f'Created roles: {len(create_user_roles)}')
)

View File

@ -0,0 +1,25 @@
# Generated by Django 2.2.7 on 2019-12-11 11:34
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('account', '0025_auto_20191210_0623'),
]
operations = [
migrations.AddField(
model_name='userrole',
name='requester',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='roles_requested', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='userrole',
name='state',
field=models.CharField(choices=[('validated', 'validated'), ('pending', 'pending'), ('cancelled', 'cancelled'), ('rejected', 'rejected')], default='pending', max_length=10, verbose_name='state'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.7 on 2019-12-11 14:44
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('establishment', '0067_auto_20191122_1244'),
('account', '0026_auto_20191211_1134'),
]
operations = [
migrations.AlterUniqueTogether(
name='userrole',
unique_together={('user', 'role', 'establishment', 'state')},
),
]

View File

@ -34,16 +34,16 @@ class Role(ProjectBaseMixin):
REVIEWER_MANGER = 6 REVIEWER_MANGER = 6
RESTAURANT_REVIEWER = 7 RESTAURANT_REVIEWER = 7
SALES_MAN = 8 SALES_MAN = 8
WINERY_REVIEWER = 9 # Establishments subtype "winery" WINERY_REVIEWER = 9 # Establishments subtype "winery"
SELLER = 10 SELLER = 10
ROLE_CHOICES = ( ROLE_CHOICES = (
(STANDARD_USER, 'Standard user'), (STANDARD_USER, _('Standard user')),
(COMMENTS_MODERATOR, 'Comments moderator'), (COMMENTS_MODERATOR, _('Comments moderator')),
(COUNTRY_ADMIN, 'Country admin'), (COUNTRY_ADMIN, _('Country admin')),
(CONTENT_PAGE_MANAGER, 'Content page manager'), (CONTENT_PAGE_MANAGER, _('Content page manager')),
(ESTABLISHMENT_MANAGER, 'Establishment manager'), (ESTABLISHMENT_MANAGER, _('Establishment manager')),
(REVIEWER_MANGER, 'Reviewer manager'), (REVIEWER_MANGER, _('Reviewer manager')),
(RESTAURANT_REVIEWER, 'Restaurant reviewer'), (RESTAURANT_REVIEWER, 'Restaurant reviewer'),
(SALES_MAN, 'Sales man'), (SALES_MAN, 'Sales man'),
(WINERY_REVIEWER, 'Winery reviewer'), (WINERY_REVIEWER, 'Winery reviewer'),
@ -93,6 +93,18 @@ class UserQuerySet(models.QuerySet):
return self.filter(oauth2_provider_refreshtoken__token=token, return self.filter(oauth2_provider_refreshtoken__token=token,
oauth2_provider_refreshtoken__expires__gt=timezone.now()) oauth2_provider_refreshtoken__expires__gt=timezone.now())
def by_role(self, role):
"""Filter by role."""
return self.filter(userrole__role=role)
def by_roles(self, roles: list):
"""Filter by roles."""
return self.filter(userrole__role__in=roles)
def establishment_admin(self, establishment):
role = Role.objects.filter(role=Role.ESTABLISHMENT_MANAGER).first()
return self.by_role(role).filter(userrole__establishment=establishment)
class User(AbstractUser): class User(AbstractUser):
"""Base user model.""" """Base user model."""
@ -116,7 +128,9 @@ class User(AbstractUser):
USERNAME_FIELD = 'username' USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email'] REQUIRED_FIELDS = ['email']
roles = models.ManyToManyField(Role, verbose_name=_('Roles'), through='UserRole') roles = models.ManyToManyField(
Role, verbose_name=_('Roles'), symmetrical=False,
through_fields=('user', 'role'), through='UserRole')
objects = UserManager.from_queryset(UserQuerySet)() objects = UserManager.from_queryset(UserQuerySet)()
class Meta: class Meta:
@ -301,14 +315,33 @@ class User(AbstractUser):
class UserRole(ProjectBaseMixin): class UserRole(ProjectBaseMixin):
"""UserRole model.""" """UserRole model."""
user = models.ForeignKey('account.User', VALIDATED = 'validated'
verbose_name=_('User'), PENDING = 'pending'
on_delete=models.CASCADE) CANCELLED = 'cancelled'
role = models.ForeignKey(Role, verbose_name=_('Role'), on_delete=models.SET_NULL, null=True) REJECTED = 'rejected'
establishment = models.ForeignKey(Establishment, verbose_name=_('Establishment'),
on_delete=models.SET_NULL, null=True, blank=True) STATE_CHOICES = (
(VALIDATED, _('validated')),
(PENDING, _('pending')),
(CANCELLED, _('cancelled')),
(REJECTED, _('rejected'))
)
user = models.ForeignKey(
'account.User', verbose_name=_('User'), on_delete=models.CASCADE)
role = models.ForeignKey(
Role, verbose_name=_('Role'), on_delete=models.SET_NULL, null=True)
establishment = models.ForeignKey(
Establishment, verbose_name=_('Establishment'),
on_delete=models.SET_NULL, null=True, blank=True)
state = models.CharField(
_('state'), choices=STATE_CHOICES, max_length=10, default=PENDING)
requester = models.ForeignKey(
'account.User', blank=True, null=True, default=None, related_name='roles_requested',
on_delete=models.SET_NULL)
class Meta: class Meta:
unique_together = ['user', 'role'] unique_together = ['user', 'role', 'establishment', 'state']
class OldRole(models.Model): class OldRole(models.Model):

View File

@ -0,0 +1,27 @@
# Generated by Django 2.2.7 on 2019-12-15 21:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('collection', '0023_advertorial'),
]
operations = [
migrations.AddField(
model_name='collection',
name='rank',
field=models.IntegerField(default=None, null=True),
),
migrations.AlterField(
model_name='collection',
name='start',
field=models.DateTimeField(blank=True, default=None, null=True, verbose_name='start'),
),
migrations.RemoveField(
model_name='collection',
name='description',
)
]

View File

@ -6,9 +6,10 @@ from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from utils.models import ProjectBaseMixin, URLImageMixin from utils.models import (
from utils.models import TJSONField ProjectBaseMixin, TJSONField, TranslatedFieldsMixin,
from utils.models import TranslatedFieldsMixin URLImageMixin,
)
from utils.querysets import RelatedObjectsCountMixin from utils.querysets import RelatedObjectsCountMixin
@ -24,7 +25,8 @@ class CollectionNameMixin(models.Model):
class CollectionDateMixin(models.Model): class CollectionDateMixin(models.Model):
"""CollectionDate mixin""" """CollectionDate mixin"""
start = models.DateTimeField(_('start')) start = models.DateTimeField(blank=True, null=True, default=None,
verbose_name=_('start'))
end = models.DateTimeField(blank=True, null=True, default=None, end = models.DateTimeField(blank=True, null=True, default=None,
verbose_name=_('end')) verbose_name=_('end'))
@ -73,13 +75,15 @@ class Collection(ProjectBaseMixin, CollectionDateMixin,
block_size = JSONField( block_size = JSONField(
_('collection block properties'), null=True, blank=True, _('collection block properties'), null=True, blank=True,
default=None, help_text='{"width": "250px", "height":"250px"}') default=None, help_text='{"width": "250px", "height":"250px"}')
description = TJSONField( # description = TJSONField(
_('description'), null=True, blank=True, # _('description'), null=True, blank=True,
default=None, help_text='{"en-GB":"some text"}') # default=None, help_text='{"en-GB":"some text"}')
slug = models.SlugField(max_length=50, unique=True, slug = models.SlugField(max_length=50, unique=True,
verbose_name=_('Collection slug'), editable=True, null=True) verbose_name=_('Collection slug'), editable=True, null=True)
old_id = models.IntegerField(null=True, blank=True) old_id = models.IntegerField(null=True, blank=True)
rank = models.IntegerField(null=True, default=None)
objects = CollectionQuerySet.as_manager() objects = CollectionQuerySet.as_manager()
class Meta: class Meta:
@ -108,20 +112,29 @@ class Collection(ProjectBaseMixin, CollectionDateMixin,
@property @property
def related_object_names(self) -> list: def related_object_names(self) -> list:
"""Return related object names.""" """Return related object names."""
raw_object_names = [] raw_object_names = {}
for related_object in [related_object.name for related_object in self._related_objects]: for related_object in [(related_object.id, related_object.name) for related_object in self._related_objects]:
instances = getattr(self, f'{related_object}') instances = getattr(self, f'{related_object[1]}')
if instances.exists(): if instances.exists():
for instance in instances.all(): for instance in instances.all():
raw_object_names.append(instance.slug if hasattr(instance, 'slug') else None) raw_object_names[related_object[0]] = instance.slug if hasattr(instance, 'slug') else None
# parse slugs # parse slugs
object_names = [] related_objects = []
object_names = set()
re_pattern = r'[\w]+' re_pattern = r'[\w]+'
for raw_name in raw_object_names: for object_id in raw_object_names:
result = re.findall(re_pattern, raw_name) result = re.findall(re_pattern, raw_object_names[object_id])
if result: object_names.append(' '.join(result).capitalize()) if result:
return set(object_names) name = ' '.join(result).capitalize()
if name not in object_names:
related_objects.append({
'id': object_id,
'name': name
})
object_names.add(name)
return related_objects
class GuideTypeQuerySet(models.QuerySet): class GuideTypeQuerySet(models.QuerySet):

View File

@ -7,7 +7,8 @@ from location.models import Country
from location.serializers import CountrySimpleSerializer from location.serializers import CountrySimpleSerializer
from product.models import Product from product.models import Product
from utils.exceptions import ( from utils.exceptions import (
BindingObjectNotFound, RemovedBindingObjectNotFound, ObjectAlreadyAdded BindingObjectNotFound, ObjectAlreadyAdded,
RemovedBindingObjectNotFound,
) )
@ -33,13 +34,14 @@ class CollectionBackOfficeSerializer(CollectionBaseSerializer):
'on_top', 'on_top',
'country', 'country',
'country_id', 'country_id',
'block_size', # 'block_size',
'description', # 'description',
'slug', 'slug',
'start', # 'start',
'end', # 'end',
'count_related_objects', 'count_related_objects',
'related_object_names', 'related_object_names',
'rank',
] ]
@ -68,15 +70,15 @@ class CollectionBindObjectSerializer(serializers.Serializer):
attrs['collection'] = collection attrs['collection'] = collection
if obj_type == self.ESTABLISHMENT: if obj_type == self.ESTABLISHMENT:
establishment = Establishment.objects.filter(pk=obj_id).\ establishment = Establishment.objects.filter(pk=obj_id). \
first() first()
if not establishment: if not establishment:
raise BindingObjectNotFound() raise BindingObjectNotFound()
if request.method == 'POST' and collection.establishments.\ if request.method == 'POST' and collection.establishments. \
filter(pk=establishment.pk).exists(): filter(pk=establishment.pk).exists():
raise ObjectAlreadyAdded() raise ObjectAlreadyAdded()
if request.method == 'DELETE' and not collection.\ if request.method == 'DELETE' and not collection. \
establishments.filter(pk=establishment.pk).\ establishments.filter(pk=establishment.pk). \
exists(): exists():
raise RemovedBindingObjectNotFound() raise RemovedBindingObjectNotFound()
attrs['related_object'] = establishment attrs['related_object'] = establishment
@ -84,10 +86,10 @@ class CollectionBindObjectSerializer(serializers.Serializer):
product = Product.objects.filter(pk=obj_id).first() product = Product.objects.filter(pk=obj_id).first()
if not product: if not product:
raise BindingObjectNotFound() raise BindingObjectNotFound()
if request.method == 'POST' and collection.products.\ if request.method == 'POST' and collection.products. \
filter(pk=product.pk).exists(): filter(pk=product.pk).exists():
raise ObjectAlreadyAdded() raise ObjectAlreadyAdded()
if request.method == 'DELETE' and not collection.products.\ if request.method == 'DELETE' and not collection.products. \
filter(pk=product.pk).exists(): filter(pk=product.pk).exists():
raise RemovedBindingObjectNotFound() raise RemovedBindingObjectNotFound()
attrs['related_object'] = product attrs['related_object'] = product

View File

@ -1,4 +1,5 @@
"""Collection common urlpaths.""" """Collection common urlpaths."""
from django.urls import path
from rest_framework.routers import SimpleRouter from rest_framework.routers import SimpleRouter
from collection.views import back as views from collection.views import back as views
@ -8,3 +9,4 @@ router = SimpleRouter()
router.register(r'', views.CollectionBackOfficeViewSet) router.register(r'', views.CollectionBackOfficeViewSet)
urlpatterns = router.urls urlpatterns = router.urls

View File

@ -1,5 +1,6 @@
from rest_framework import permissions from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets, mixins from rest_framework import mixins, permissions, viewsets
from rest_framework.filters import OrderingFilter
from collection import models from collection import models
from collection.serializers import back as serializers from collection.serializers import back as serializers
@ -31,9 +32,13 @@ class CollectionBackOfficeViewSet(mixins.CreateModelMixin,
permission_classes = (permissions.IsAuthenticated,) permission_classes = (permissions.IsAuthenticated,)
queryset = models.Collection.objects.all() queryset = models.Collection.objects.all()
filter_backends = [DjangoFilterBackend, OrderingFilter]
serializer_class = serializers.CollectionBackOfficeSerializer serializer_class = serializers.CollectionBackOfficeSerializer
bind_object_serializer_class = serializers.CollectionBindObjectSerializer bind_object_serializer_class = serializers.CollectionBindObjectSerializer
ordering_fields = ('rank', 'start')
ordering = ('-start', )
def perform_binding(self, serializer): def perform_binding(self, serializer):
data = serializer.validated_data data = serializer.validated_data
collection = data.pop('collection') collection = data.pop('collection')

View File

@ -541,9 +541,15 @@ class Establishment(GalleryModelMixin, ProjectBaseMixin, URLImageMixin,
def visible_tags(self): def visible_tags(self):
return super().visible_tags \ return super().visible_tags \
.exclude(category__index_name__in=['guide', 'collection', 'purchased_item', .exclude(category__index_name__in=['guide', 'collection', 'purchased_item',
'business_tag', 'business_tags_de', 'tag']) 'business_tag', 'business_tags_de']) \
.exclude(value__in=['rss', 'rss_selection'])
# todo: recalculate toque_number # todo: recalculate toque_number
@property
def visible_tags_detail(self):
"""Removes some tags from detail Establishment representation"""
return self.visible_tags.exclude(category__index_name__in=['tag'])
def recalculate_toque_number(self): def recalculate_toque_number(self):
toque_number = 0 toque_number = 0
if self.address and self.public_mark: if self.address and self.public_mark:

View File

@ -324,3 +324,14 @@ class EstablishmentNoteListCreateSerializer(EstablishmentNoteBaseSerializer):
"""Return establishment instance from view.""" """Return establishment instance from view."""
if self.serializer_view: if self.serializer_view:
return self.serializer_view.get_object() return self.serializer_view.get_object()
class EstablishmentAdminListSerializer(UserShortSerializer):
"""Establishment admin serializer."""
class Meta:
model = UserShortSerializer.Meta.model
fields = [
'id',
'username',
'email'
]

View File

@ -28,6 +28,8 @@ urlpatterns = [
name='note-list-create'), name='note-list-create'),
path('slug/<slug:slug>/notes/<int:note_pk>/', views.EstablishmentNoteRUDView.as_view(), path('slug/<slug:slug>/notes/<int:note_pk>/', views.EstablishmentNoteRUDView.as_view(),
name='note-rud'), name='note-rud'),
path('slug/<slug:slug>/admin/', views.EstablishmentAdminView.as_view(),
name='establishment-admin-list'),
path('menus/', views.MenuListCreateView.as_view(), name='menu-list'), path('menus/', views.MenuListCreateView.as_view(), name='menu-list'),
path('menus/<int:pk>/', views.MenuRUDView.as_view(), name='menu-rud'), path('menus/<int:pk>/', views.MenuRUDView.as_view(), name='menu-rud'),
path('plates/', views.PlateListCreateView.as_view(), name='plates'), path('plates/', views.PlateListCreateView.as_view(), name='plates'),

View File

@ -4,6 +4,7 @@ from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import generics, permissions, status from rest_framework import generics, permissions, status
from account.models import User
from establishment import filters, models, serializers from establishment import filters, models, serializers
from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer
from utils.permissions import IsCountryAdmin, IsEstablishmentManager, IsWineryReviewer from utils.permissions import IsCountryAdmin, IsEstablishmentManager, IsWineryReviewer
@ -380,3 +381,14 @@ class EstablishmentPositionListView(generics.ListAPIView):
permission_classes = (permissions.AllowAny,) permission_classes = (permissions.AllowAny,)
queryset = models.Position.objects.all() queryset = models.Position.objects.all()
serializer_class = serializers.PositionBackSerializer serializer_class = serializers.PositionBackSerializer
class EstablishmentAdminView(generics.ListAPIView):
"""Establishment admin list view."""
serializer_class = serializers.EstablishmentAdminListSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly, )
def get_queryset(self):
establishment = get_object_or_404(
models.Establishment, slug=self.kwargs['slug'])
return User.objects.establishment_admin(establishment).distinct()

View File

@ -1,7 +1,7 @@
"""News app views.""" """News app views."""
from django.conf import settings from django.conf import settings
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from rest_framework import generics, permissions from rest_framework import generics, permissions, response
from news import filters, models, serializers from news import filters, models, serializers
from rating.tasks import add_rating from rating.tasks import add_rating
@ -99,7 +99,10 @@ class NewsBackOfficeLCView(NewsBackOfficeMixinView,
def get_queryset(self): def get_queryset(self):
"""Override get_queryset method.""" """Override get_queryset method."""
return super().get_queryset().with_extended_related() qs = super().get_queryset().with_extended_related()
if self.request.country_code:
qs = qs.by_country_code(self.request.country_code)
return qs
class NewsBackOfficeGalleryCreateDestroyView(NewsBackOfficeMixinView, class NewsBackOfficeGalleryCreateDestroyView(NewsBackOfficeMixinView,
@ -107,6 +110,13 @@ class NewsBackOfficeGalleryCreateDestroyView(NewsBackOfficeMixinView,
"""Resource for a create gallery for news for back-office users.""" """Resource for a create gallery for news for back-office users."""
serializer_class = serializers.NewsBackOfficeGallerySerializer serializer_class = serializers.NewsBackOfficeGallerySerializer
def create(self, request, *args, **kwargs):
_ = super().create(request, *args, **kwargs)
news_qs = self.filter_queryset(self.get_queryset())
return response.Response(
data=serializers.NewsDetailSerializer(get_object_or_404(news_qs, pk=kwargs.get('pk'))).data
)
def get_object(self): def get_object(self):
""" """
Returns the object the view is displaying. Returns the object the view is displaying.

View File

@ -12,24 +12,9 @@ from search_indexes import serializers, filters, utils
from search_indexes.documents import EstablishmentDocument, NewsDocument from search_indexes.documents import EstablishmentDocument, NewsDocument
from search_indexes.documents.product import ProductDocument from search_indexes.documents.product import ProductDocument
from utils.pagination import ESDocumentPagination from utils.pagination import ESDocumentPagination
from tag.models import TagCategory
class CustomBaseDocumentViewSet(BaseDocumentViewSet): class NewsDocumentViewSet(BaseDocumentViewSet):
def __init__(self, *args, **kwargs):
if self.filter_fields:
for name in TagCategory.objects.all().values('index_name'):
self.filter_fields.update({
f'{name["index_name"]}_id': {
'field': 'tags.id',
'lookups': [constants.LOOKUP_QUERY_IN]
}
})
super().__init__(*args, **kwargs)
class NewsDocumentViewSet(CustomBaseDocumentViewSet):
"""News document ViewSet.""" """News document ViewSet."""
document = NewsDocument document = NewsDocument
@ -76,11 +61,18 @@ class NewsDocumentViewSet(CustomBaseDocumentViewSet):
) )
filter_fields = { filter_fields = {
'tags_id': {
'field': 'tags.id',
'lookups': [
constants.LOOKUP_QUERY_IN,
constants.LOOKUP_QUERY_EXCLUDE,
],
},
'tag': { 'tag': {
'field': 'tags.id', 'field': 'tags.id',
'lookups': [ 'lookups': [
constants.LOOKUP_QUERY_IN, constants.LOOKUP_QUERY_IN,
constants.LOOKUP_QUERY_EXCLUDE constants.LOOKUP_QUERY_EXCLUDE,
] ]
}, },
'tag_value': { 'tag_value': {
@ -108,7 +100,7 @@ class MobileNewsDocumentViewSet(NewsDocumentViewSet):
] ]
class EstablishmentDocumentViewSet(CustomBaseDocumentViewSet): class EstablishmentDocumentViewSet(BaseDocumentViewSet):
"""Establishment document ViewSet.""" """Establishment document ViewSet."""
document = EstablishmentDocument document = EstablishmentDocument
@ -333,7 +325,7 @@ class MobileEstablishmentDocumentViewSet(EstablishmentDocumentViewSet):
] ]
class ProductDocumentViewSet(CustomBaseDocumentViewSet): class ProductDocumentViewSet(BaseDocumentViewSet):
"""Product document ViewSet.""" """Product document ViewSet."""
document = ProductDocument document = ProductDocument
@ -405,7 +397,7 @@ class ProductDocumentViewSet(CustomBaseDocumentViewSet):
'lookups': [constants.LOOKUP_QUERY_IN], 'lookups': [constants.LOOKUP_QUERY_IN],
}, },
'country': { 'country': {
'field': 'establishment.address.city.country.code', 'field': 'establishment.city.country.code',
}, },
'wine_colors_id': { 'wine_colors_id': {
'field': 'wine_colors.id', 'field': 'wine_colors.id',

View File

@ -123,7 +123,9 @@ class FiltersTagCategoryBaseSerializer(serializers.ModelSerializer):
return obj in ['open_now', ] return obj in ['open_now', ]
def get_param_name(self, obj): def get_param_name(self, obj):
return f'{obj.index_name}_id__in' if obj.index_name == 'wine-color':
return 'wine_colors_id__in'
return 'tags_id__in'
def get_fields(self, *args, **kwargs): def get_fields(self, *args, **kwargs):
fields = super(FiltersTagCategoryBaseSerializer, self).get_fields() fields = super(FiltersTagCategoryBaseSerializer, self).get_fields()

View File

@ -63,9 +63,20 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
"""ViewSet for TagCategory model.""" """ViewSet for TagCategory model."""
serializer_class = serializers.FiltersTagCategoryBaseSerializer serializer_class = serializers.FiltersTagCategoryBaseSerializer
index_name_to_order = {
'open_now': 9,
'works_noon': 8,
'works_evening': 7,
'pop': 6,
'category': 5,
'toque_number': 4,
'cuisine': 3,
'moment': 2,
'service': 1,
}
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset().exclude(public=False))
serializer = self.get_serializer(queryset, many=True) serializer = self.get_serializer(queryset, many=True)
result_list = serializer.data result_list = serializer.data
@ -77,7 +88,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
elif query_params.get('product_type'): elif query_params.get('product_type'):
params_type = query_params.get('product_type') params_type = query_params.get('product_type')
week_days = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday") week_days = tuple(map(_, ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")))
flags = ('toque_number', 'wine_region', 'works_noon', 'works_evening', 'works_now', 'works_at_weekday') flags = ('toque_number', 'wine_region', 'works_noon', 'works_evening', 'works_now', 'works_at_weekday')
filter_flags = {flag_name: False for flag_name in flags} filter_flags = {flag_name: False for flag_name in flags}
additional_flags = [] additional_flags = []
@ -94,19 +105,6 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
for flag_name in additional_flags: for flag_name in additional_flags:
filter_flags[flag_name] = True filter_flags[flag_name] = True
if filter_flags['toque_number']:
toques = {
"index_name": "toque_number",
"label_translated": "Toques",
"param_name": "toque_number__in",
"filters": [{
"id": toque_id,
"index_name": "toque_%d" % toque_id,
"label_translated": "Toque %d" % toque_id
} for toque_id in range(6)]
}
result_list.append(toques)
if request.query_params.get('product_type') == ProductType.WINE: if request.query_params.get('product_type') == ProductType.WINE:
wine_region_id = query_params.get('wine_region_id__in') wine_region_id = query_params.get('wine_region_id__in')
@ -129,11 +127,30 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
result_list.append(wine_regions) result_list.append(wine_regions)
for item in result_list:
if 'filters' in item:
item['filters'].sort(key=lambda x: x.get('label_translated'))
if filter_flags['toque_number']:
toques = {
"index_name": "toque_number",
"label_translated": "Toques",
"param_name": "toque_number__in",
'type': 'toque',
"filters": [{
"id": toque_id,
"index_name": "toque_%d" % toque_id,
"label_translated": "Toque %d" % toque_id
} for toque_id in range(6)]
}
result_list.append(toques)
if filter_flags['works_noon']: if filter_flags['works_noon']:
works_noon = { works_noon = {
"index_name": "works_noon", "index_name": "works_noon",
"label_translated": "Open noon", "label_translated": "Open noon",
"param_name": "works_noon__in", "param_name": "works_noon__in",
'type': 'weekday',
"filters": [{ "filters": [{
"id": weekday, "id": weekday,
"index_name": week_days[weekday].lower(), "index_name": week_days[weekday].lower(),
@ -148,6 +165,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
"index_name": "works_evening", "index_name": "works_evening",
"label_translated": "Open evening", "label_translated": "Open evening",
"param_name": "works_evening__in", "param_name": "works_evening__in",
'type': 'weekday',
"filters": [{ "filters": [{
"id": weekday, "id": weekday,
"index_name": week_days[weekday].lower(), "index_name": week_days[weekday].lower(),
@ -161,7 +179,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
"index_name": "open_now", "index_name": "open_now",
"label_translated": "Open now", "label_translated": "Open now",
"param_name": "open_now", "param_name": "open_now",
"type": True "type": 'bool',
} }
result_list.append(works_now) result_list.append(works_now)
@ -170,6 +188,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
"index_name": "works_at_weekday", "index_name": "works_at_weekday",
"label_translated": "Works at weekday", "label_translated": "Works at weekday",
"param_name": "works_at_weekday__in", "param_name": "works_at_weekday__in",
'type': 'weekday',
"filters": [{ "filters": [{
"id": weekday, "id": weekday,
"index_name": week_days[weekday].lower(), "index_name": week_days[weekday].lower(),
@ -180,7 +199,17 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
search_view_class = self.define_search_view_by_request(request) search_view_class = self.define_search_view_by_request(request)
facets = search_view_class.as_view({'get': 'list'})(self.mutate_request(self.request)).data['facets'] facets = search_view_class.as_view({'get': 'list'})(self.mutate_request(self.request)).data['facets']
return Response(self.remove_empty_filters(result_list, facets)) result_list = self.remove_empty_filters(result_list, facets)
tag_category = list(filter(lambda x: x.get('index_name') == 'tag', result_list))
result_list = [category for category in result_list if category.get('index_name') != 'tag']
if len(tag_category):
tag_category = list(filter(lambda x: x.get('index_name') == 'pop', tag_category[0]['filters']))
if len(tag_category): # we have Pop tag in our results
tag_category = tag_category[0]
tag_category['param_name'] = 'tags_id__in'
result_list.append(tag_category)
result_list.sort(key=lambda x: self.index_name_to_order.get(x.get('index_name'), 0), reverse=True)
return Response(result_list)
@staticmethod @staticmethod
def mutate_request(request): def mutate_request(request):
@ -213,6 +242,46 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet):
@staticmethod @staticmethod
def remove_empty_filters(filters, facets): def remove_empty_filters(filters, facets):
# parse facets
if facets.get('_filter_tag'):
tags_to_preserve = list(map(lambda el: el['key'], facets['_filter_tag']['tag']['buckets']))
if facets.get('_filter_wine_colors'):
wine_colors_to_preserve = list(
map(lambda el: el['key'], facets['_filter_wine_colors']['wine_colors']['buckets']))
if facets.get('_filter_wine_region_id'):
wine_regions_to_preserve = list(
map(lambda el: el['key'], facets['_filter_wine_region_id']['wine_region_id']['buckets']))
if facets.get('_filter_toque_number'):
toque_numbers = list(map(lambda el: el['key'], facets['_filter_toque_number']['toque_number']['buckets']))
if facets.get('_filter_works_noon'):
works_noon = list(map(lambda el: el['key'], facets['_filter_works_noon']['works_noon']['buckets']))
if facets.get('_filter_works_evening'):
works_evening = list(map(lambda el: el['key'], facets['_filter_works_evening']['works_evening']['buckets']))
if facets.get('_filter_works_at_weekday'):
works_at_weekday = list(
map(lambda el: el['key'], facets['_filter_works_at_weekday']['works_at_weekday']['buckets']))
if facets.get('_filter_works_now'):
works_now = list(map(lambda el: el['key'], facets['_filter_works_now']['works_now']['buckets']))
# remove empty filters
for category in filters:
param_name = category.get('param_name')
if param_name == 'tags_id__in':
category['filters'] = list(filter(lambda tag: tag['id'] in tags_to_preserve, category['filters']))
elif param_name == 'wine_colors_id__in':
category['filters'] = list(
filter(lambda tag: tag['id'] in wine_colors_to_preserve, category['filters']))
elif param_name == 'wine_region_id__in':
category['filters'] = list(
filter(lambda tag: tag['id'] in wine_regions_to_preserve, category['filters']))
elif param_name == 'toque_number__in':
category['filters'] = list(filter(lambda tag: tag['id'] in toque_numbers, category['filters']))
elif param_name == 'works_noon__in':
category['filters'] = list(filter(lambda tag: tag['id'] in works_noon, category['filters']))
elif param_name == 'works_evening__in':
category['filters'] = list(filter(lambda tag: tag['id'] in works_evening, category['filters']))
elif param_name == 'works_at_weekday__in':
category['filters'] = list(filter(lambda tag: tag['id'] in works_at_weekday, category['filters']))
return filters return filters

View File

@ -1224,6 +1224,21 @@ class Footers(MigrateMixin):
db_table = 'footers' db_table = 'footers'
class OwnershipAffs(MigrateMixin):
using = 'legacy'
role = models.CharField(max_length=255, blank=True, null=True)
state = models.CharField(max_length=255, blank=True, null=True)
account_id = models.IntegerField(blank=True, null=True)
establishment_id = models.IntegerField(blank=True, null=True)
created_at = models.DateTimeField()
updated_at = models.DateTimeField()
requester_id = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'ownership_affs'
class Panels(MigrateMixin): class Panels(MigrateMixin):
using = 'legacy' using = 'legacy'

12
db_migration_resolve.txt Normal file
View File

@ -0,0 +1,12 @@
В случае возникновения проблемы с применением миграции account 0027:
1 Удаляем unique together constrain для app - account
ALTER TABLE account_userrole
DROP CONSTRAINT account_userrole_user_id_role_id_26fa14c4_uniq;
2 Правим миграцию 0023
migrations.AlterUniqueTogether(
name='userrole',
unique_together=set(),
),
3 Применяем account 0027
4 Возвращаем миграцию account 0023, в исходное состояние