diff --git a/apps/account/management/commands/add_ownership.py b/apps/account/management/commands/add_ownership.py new file mode 100644 index 00000000..84926d9c --- /dev/null +++ b/apps/account/management/commands/add_ownership.py @@ -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)}') + ) diff --git a/apps/account/migrations/0026_auto_20191211_1134.py b/apps/account/migrations/0026_auto_20191211_1134.py new file mode 100644 index 00000000..7325c9a7 --- /dev/null +++ b/apps/account/migrations/0026_auto_20191211_1134.py @@ -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'), + ), + ] diff --git a/apps/account/migrations/0027_auto_20191211_1444.py b/apps/account/migrations/0027_auto_20191211_1444.py new file mode 100644 index 00000000..ed0886e7 --- /dev/null +++ b/apps/account/migrations/0027_auto_20191211_1444.py @@ -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')}, + ), + ] diff --git a/apps/account/models.py b/apps/account/models.py index 70a3cd69..b48a419c 100644 --- a/apps/account/models.py +++ b/apps/account/models.py @@ -34,16 +34,16 @@ class Role(ProjectBaseMixin): REVIEWER_MANGER = 6 RESTAURANT_REVIEWER = 7 SALES_MAN = 8 - WINERY_REVIEWER = 9 # Establishments subtype "winery" + WINERY_REVIEWER = 9 # Establishments subtype "winery" SELLER = 10 ROLE_CHOICES = ( - (STANDARD_USER, 'Standard user'), - (COMMENTS_MODERATOR, 'Comments moderator'), - (COUNTRY_ADMIN, 'Country admin'), - (CONTENT_PAGE_MANAGER, 'Content page manager'), - (ESTABLISHMENT_MANAGER, 'Establishment manager'), - (REVIEWER_MANGER, 'Reviewer manager'), + (STANDARD_USER, _('Standard user')), + (COMMENTS_MODERATOR, _('Comments moderator')), + (COUNTRY_ADMIN, _('Country admin')), + (CONTENT_PAGE_MANAGER, _('Content page manager')), + (ESTABLISHMENT_MANAGER, _('Establishment manager')), + (REVIEWER_MANGER, _('Reviewer manager')), (RESTAURANT_REVIEWER, 'Restaurant reviewer'), (SALES_MAN, 'Sales man'), (WINERY_REVIEWER, 'Winery reviewer'), @@ -93,6 +93,18 @@ class UserQuerySet(models.QuerySet): return self.filter(oauth2_provider_refreshtoken__token=token, 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): """Base user model.""" @@ -116,7 +128,9 @@ class User(AbstractUser): USERNAME_FIELD = 'username' 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)() class Meta: @@ -301,14 +315,33 @@ class User(AbstractUser): class UserRole(ProjectBaseMixin): """UserRole model.""" - 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) + VALIDATED = 'validated' + PENDING = 'pending' + CANCELLED = 'cancelled' + REJECTED = 'rejected' + + 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: - unique_together = ['user', 'role'] + unique_together = ['user', 'role', 'establishment', 'state'] class OldRole(models.Model): diff --git a/apps/collection/migrations/0024_auto_20191215_2156.py b/apps/collection/migrations/0024_auto_20191215_2156.py new file mode 100644 index 00000000..1b494867 --- /dev/null +++ b/apps/collection/migrations/0024_auto_20191215_2156.py @@ -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', + ) + ] diff --git a/apps/collection/models.py b/apps/collection/models.py index 7acd9991..099491ac 100644 --- a/apps/collection/models.py +++ b/apps/collection/models.py @@ -6,9 +6,10 @@ from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.utils.translation import gettext_lazy as _ -from utils.models import ProjectBaseMixin, URLImageMixin -from utils.models import TJSONField -from utils.models import TranslatedFieldsMixin +from utils.models import ( + ProjectBaseMixin, TJSONField, TranslatedFieldsMixin, + URLImageMixin, +) from utils.querysets import RelatedObjectsCountMixin @@ -24,7 +25,8 @@ class CollectionNameMixin(models.Model): class CollectionDateMixin(models.Model): """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, verbose_name=_('end')) @@ -73,13 +75,15 @@ class Collection(ProjectBaseMixin, CollectionDateMixin, block_size = JSONField( _('collection block properties'), null=True, blank=True, default=None, help_text='{"width": "250px", "height":"250px"}') - description = TJSONField( - _('description'), null=True, blank=True, - default=None, help_text='{"en-GB":"some text"}') + # description = TJSONField( + # _('description'), null=True, blank=True, + # default=None, help_text='{"en-GB":"some text"}') slug = models.SlugField(max_length=50, unique=True, verbose_name=_('Collection slug'), editable=True, null=True) old_id = models.IntegerField(null=True, blank=True) + rank = models.IntegerField(null=True, default=None) + objects = CollectionQuerySet.as_manager() class Meta: @@ -108,20 +112,29 @@ class Collection(ProjectBaseMixin, CollectionDateMixin, @property def related_object_names(self) -> list: """Return related object names.""" - raw_object_names = [] - for related_object in [related_object.name for related_object in self._related_objects]: - instances = getattr(self, f'{related_object}') + raw_object_names = {} + for related_object in [(related_object.id, related_object.name) for related_object in self._related_objects]: + instances = getattr(self, f'{related_object[1]}') if instances.exists(): 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 - object_names = [] + related_objects = [] + object_names = set() re_pattern = r'[\w]+' - for raw_name in raw_object_names: - result = re.findall(re_pattern, raw_name) - if result: object_names.append(' '.join(result).capitalize()) - return set(object_names) + for object_id in raw_object_names: + result = re.findall(re_pattern, raw_object_names[object_id]) + if result: + 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): diff --git a/apps/collection/serializers/back.py b/apps/collection/serializers/back.py index 48c25f6c..bdc97e91 100644 --- a/apps/collection/serializers/back.py +++ b/apps/collection/serializers/back.py @@ -7,7 +7,8 @@ from location.models import Country from location.serializers import CountrySimpleSerializer from product.models import Product from utils.exceptions import ( - BindingObjectNotFound, RemovedBindingObjectNotFound, ObjectAlreadyAdded + BindingObjectNotFound, ObjectAlreadyAdded, + RemovedBindingObjectNotFound, ) @@ -33,13 +34,14 @@ class CollectionBackOfficeSerializer(CollectionBaseSerializer): 'on_top', 'country', 'country_id', - 'block_size', - 'description', + # 'block_size', + # 'description', 'slug', - 'start', - 'end', + # 'start', + # 'end', 'count_related_objects', 'related_object_names', + 'rank', ] @@ -68,15 +70,15 @@ class CollectionBindObjectSerializer(serializers.Serializer): attrs['collection'] = collection if obj_type == self.ESTABLISHMENT: - establishment = Establishment.objects.filter(pk=obj_id).\ + establishment = Establishment.objects.filter(pk=obj_id). \ first() if not establishment: raise BindingObjectNotFound() - if request.method == 'POST' and collection.establishments.\ + if request.method == 'POST' and collection.establishments. \ filter(pk=establishment.pk).exists(): raise ObjectAlreadyAdded() - if request.method == 'DELETE' and not collection.\ - establishments.filter(pk=establishment.pk).\ + if request.method == 'DELETE' and not collection. \ + establishments.filter(pk=establishment.pk). \ exists(): raise RemovedBindingObjectNotFound() attrs['related_object'] = establishment @@ -84,10 +86,10 @@ class CollectionBindObjectSerializer(serializers.Serializer): product = Product.objects.filter(pk=obj_id).first() if not product: raise BindingObjectNotFound() - if request.method == 'POST' and collection.products.\ + if request.method == 'POST' and collection.products. \ filter(pk=product.pk).exists(): raise ObjectAlreadyAdded() - if request.method == 'DELETE' and not collection.products.\ + if request.method == 'DELETE' and not collection.products. \ filter(pk=product.pk).exists(): raise RemovedBindingObjectNotFound() attrs['related_object'] = product diff --git a/apps/collection/urls/back.py b/apps/collection/urls/back.py index 6a6dbd54..972f5285 100644 --- a/apps/collection/urls/back.py +++ b/apps/collection/urls/back.py @@ -1,4 +1,5 @@ """Collection common urlpaths.""" +from django.urls import path from rest_framework.routers import SimpleRouter from collection.views import back as views @@ -8,3 +9,4 @@ router = SimpleRouter() router.register(r'', views.CollectionBackOfficeViewSet) urlpatterns = router.urls + diff --git a/apps/collection/views/back.py b/apps/collection/views/back.py index ff924073..b8ff3181 100644 --- a/apps/collection/views/back.py +++ b/apps/collection/views/back.py @@ -1,5 +1,6 @@ -from rest_framework import permissions -from rest_framework import viewsets, mixins +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework import mixins, permissions, viewsets +from rest_framework.filters import OrderingFilter from collection import models from collection.serializers import back as serializers @@ -31,9 +32,13 @@ class CollectionBackOfficeViewSet(mixins.CreateModelMixin, permission_classes = (permissions.IsAuthenticated,) queryset = models.Collection.objects.all() + filter_backends = [DjangoFilterBackend, OrderingFilter] 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') diff --git a/apps/establishment/models.py b/apps/establishment/models.py index ab7f14fa..5ff6f921 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -541,9 +541,15 @@ class Establishment(GalleryModelMixin, ProjectBaseMixin, URLImageMixin, def visible_tags(self): return super().visible_tags \ .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 + @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): toque_number = 0 if self.address and self.public_mark: diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index a1b6cc4a..b7d429da 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -324,3 +324,14 @@ class EstablishmentNoteListCreateSerializer(EstablishmentNoteBaseSerializer): """Return establishment instance from view.""" if self.serializer_view: return self.serializer_view.get_object() + + +class EstablishmentAdminListSerializer(UserShortSerializer): + """Establishment admin serializer.""" + class Meta: + model = UserShortSerializer.Meta.model + fields = [ + 'id', + 'username', + 'email' + ] diff --git a/apps/establishment/urls/back.py b/apps/establishment/urls/back.py index ce1c7b27..b2a30917 100644 --- a/apps/establishment/urls/back.py +++ b/apps/establishment/urls/back.py @@ -28,6 +28,8 @@ urlpatterns = [ name='note-list-create'), path('slug//notes//', views.EstablishmentNoteRUDView.as_view(), name='note-rud'), + path('slug//admin/', views.EstablishmentAdminView.as_view(), + name='establishment-admin-list'), 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 ad5eafdf..febd0553 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -4,6 +4,7 @@ from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend from rest_framework import generics, permissions, status +from account.models import User from establishment import filters, models, serializers from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer from utils.permissions import IsCountryAdmin, IsEstablishmentManager, IsWineryReviewer @@ -380,3 +381,14 @@ class EstablishmentPositionListView(generics.ListAPIView): permission_classes = (permissions.AllowAny,) queryset = models.Position.objects.all() 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() diff --git a/apps/news/views.py b/apps/news/views.py index c8acb3ac..fe9a75e7 100644 --- a/apps/news/views.py +++ b/apps/news/views.py @@ -1,7 +1,7 @@ """News app views.""" from django.conf import settings 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 rating.tasks import add_rating @@ -99,7 +99,10 @@ class NewsBackOfficeLCView(NewsBackOfficeMixinView, def get_queryset(self): """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, @@ -107,6 +110,13 @@ class NewsBackOfficeGalleryCreateDestroyView(NewsBackOfficeMixinView, """Resource for a create gallery for news for back-office users.""" 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): """ Returns the object the view is displaying. diff --git a/apps/search_indexes/views.py b/apps/search_indexes/views.py index e567f212..f088bf8b 100644 --- a/apps/search_indexes/views.py +++ b/apps/search_indexes/views.py @@ -12,24 +12,9 @@ from search_indexes import serializers, filters, utils from search_indexes.documents import EstablishmentDocument, NewsDocument from search_indexes.documents.product import ProductDocument from utils.pagination import ESDocumentPagination -from tag.models import TagCategory -class CustomBaseDocumentViewSet(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): +class NewsDocumentViewSet(BaseDocumentViewSet): """News document ViewSet.""" document = NewsDocument @@ -76,11 +61,18 @@ class NewsDocumentViewSet(CustomBaseDocumentViewSet): ) filter_fields = { + 'tags_id': { + 'field': 'tags.id', + 'lookups': [ + constants.LOOKUP_QUERY_IN, + constants.LOOKUP_QUERY_EXCLUDE, + ], + }, 'tag': { 'field': 'tags.id', 'lookups': [ constants.LOOKUP_QUERY_IN, - constants.LOOKUP_QUERY_EXCLUDE + constants.LOOKUP_QUERY_EXCLUDE, ] }, 'tag_value': { @@ -108,7 +100,7 @@ class MobileNewsDocumentViewSet(NewsDocumentViewSet): ] -class EstablishmentDocumentViewSet(CustomBaseDocumentViewSet): +class EstablishmentDocumentViewSet(BaseDocumentViewSet): """Establishment document ViewSet.""" document = EstablishmentDocument @@ -333,7 +325,7 @@ class MobileEstablishmentDocumentViewSet(EstablishmentDocumentViewSet): ] -class ProductDocumentViewSet(CustomBaseDocumentViewSet): +class ProductDocumentViewSet(BaseDocumentViewSet): """Product document ViewSet.""" document = ProductDocument @@ -405,7 +397,7 @@ class ProductDocumentViewSet(CustomBaseDocumentViewSet): 'lookups': [constants.LOOKUP_QUERY_IN], }, 'country': { - 'field': 'establishment.address.city.country.code', + 'field': 'establishment.city.country.code', }, 'wine_colors_id': { 'field': 'wine_colors.id', diff --git a/apps/tag/serializers.py b/apps/tag/serializers.py index c842774b..b5e5a267 100644 --- a/apps/tag/serializers.py +++ b/apps/tag/serializers.py @@ -123,7 +123,9 @@ class FiltersTagCategoryBaseSerializer(serializers.ModelSerializer): return obj in ['open_now', ] 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): fields = super(FiltersTagCategoryBaseSerializer, self).get_fields() diff --git a/apps/tag/views.py b/apps/tag/views.py index 6a594220..2b8eb4ef 100644 --- a/apps/tag/views.py +++ b/apps/tag/views.py @@ -63,9 +63,20 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet): """ViewSet for TagCategory model.""" 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): - queryset = self.filter_queryset(self.get_queryset()) + queryset = self.filter_queryset(self.get_queryset().exclude(public=False)) serializer = self.get_serializer(queryset, many=True) result_list = serializer.data @@ -77,7 +88,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet): elif 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') filter_flags = {flag_name: False for flag_name in flags} additional_flags = [] @@ -94,19 +105,6 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet): for flag_name in additional_flags: filter_flags[flag_name] = True - if filter_flags['toque_number']: - toques = { - "index_name": "toque_number", - "label_translated": "Toques", - "param_name": "toque_number__in", - "filters": [{ - "id": toque_id, - "index_name": "toque_%d" % toque_id, - "label_translated": "Toque %d" % toque_id - } for toque_id in range(6)] - } - result_list.append(toques) - if request.query_params.get('product_type') == ProductType.WINE: wine_region_id = query_params.get('wine_region_id__in') @@ -129,11 +127,30 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet): 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']: works_noon = { "index_name": "works_noon", "label_translated": "Open noon", "param_name": "works_noon__in", + 'type': 'weekday', "filters": [{ "id": weekday, "index_name": week_days[weekday].lower(), @@ -148,6 +165,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet): "index_name": "works_evening", "label_translated": "Open evening", "param_name": "works_evening__in", + 'type': 'weekday', "filters": [{ "id": weekday, "index_name": week_days[weekday].lower(), @@ -161,7 +179,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet): "index_name": "open_now", "label_translated": "Open now", "param_name": "open_now", - "type": True + "type": 'bool', } result_list.append(works_now) @@ -170,6 +188,7 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet): "index_name": "works_at_weekday", "label_translated": "Works at weekday", "param_name": "works_at_weekday__in", + 'type': 'weekday', "filters": [{ "id": weekday, "index_name": week_days[weekday].lower(), @@ -180,7 +199,17 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet): 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'] - 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 def mutate_request(request): @@ -213,6 +242,46 @@ class FiltersTagCategoryViewSet(TagCategoryViewSet): @staticmethod 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 diff --git a/apps/transfer/models.py b/apps/transfer/models.py index 7f640a5c..8fbb7e97 100644 --- a/apps/transfer/models.py +++ b/apps/transfer/models.py @@ -1224,6 +1224,21 @@ class Footers(MigrateMixin): 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): using = 'legacy' diff --git a/db_migration_resolve.txt b/db_migration_resolve.txt new file mode 100644 index 00000000..770dac81 --- /dev/null +++ b/db_migration_resolve.txt @@ -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, в исходное состояние \ No newline at end of file