Merge branch 'develop' into feature/fix-country-region-city-transfer
This commit is contained in:
commit
181e9599e4
49
apps/account/management/commands/add_ownership.py
Normal file
49
apps/account/management/commands/add_ownership.py
Normal 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)}')
|
||||
)
|
||||
25
apps/account/migrations/0026_auto_20191211_1134.py
Normal file
25
apps/account/migrations/0026_auto_20191211_1134.py
Normal 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'),
|
||||
),
|
||||
]
|
||||
18
apps/account/migrations/0027_auto_20191211_1444.py
Normal file
18
apps/account/migrations/0027_auto_20191211_1444.py
Normal 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')},
|
||||
),
|
||||
]
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
27
apps/collection/migrations/0024_auto_20191215_2156.py
Normal file
27
apps/collection/migrations/0024_auto_20191215_2156.py
Normal 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',
|
||||
)
|
||||
]
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
]
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ urlpatterns = [
|
|||
name='note-list-create'),
|
||||
path('slug/<slug:slug>/notes/<int:note_pk>/', views.EstablishmentNoteRUDView.as_view(),
|
||||
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/<int:pk>/', views.MenuRUDView.as_view(), name='menu-rud'),
|
||||
path('plates/', views.PlateListCreateView.as_view(), name='plates'),
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
|
|
|
|||
12
db_migration_resolve.txt
Normal file
12
db_migration_resolve.txt
Normal 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, в исходное состояние
|
||||
Loading…
Reference in New Issue
Block a user