Merge remote-tracking branch 'origin/develop' into fix/hide-excess-tags
This commit is contained in:
commit
234f21e03b
152
apps/account/management/commands/add_affilations.py
Normal file
152
apps/account/management/commands/add_affilations.py
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
from account.models import OldRole, Role, User, UserRole
|
||||
from main.models import SiteSettings
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import connections, transaction
|
||||
from django.db.models import Prefetch
|
||||
from establishment.management.commands.add_position import namedtuplefetchall
|
||||
from tqdm import tqdm
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '''Add site affilations from old db to new db.
|
||||
Run after migrate account models!!!'''
|
||||
|
||||
def map_role_sql(self):
|
||||
with connections['legacy'].cursor() as cursor:
|
||||
cursor.execute('''
|
||||
select distinct
|
||||
case when role = 'news_editor' then 'CONTENT_PAGE_MANAGER'
|
||||
when role in ('reviewer', 'reviwer', 'reviewer_manager') then 'REVIEWER_MANGER'
|
||||
when role = 'admin' then 'SUPERUSER'
|
||||
when role ='community_manager' then 'COUNTRY_ADMIN'
|
||||
when role = 'site_admin' then 'COUNTRY_ADMIN'
|
||||
when role = 'wine_reviewer' then 'WINERY_REVIEWER'
|
||||
when role in ('salesman', 'sales_man') then 'SALES_MAN'
|
||||
when role = 'seller' then 'SELLER'
|
||||
else role
|
||||
end as new_role,
|
||||
case when role = 'GUEST' then null else role end as role
|
||||
from
|
||||
(
|
||||
SELECT
|
||||
DISTINCT
|
||||
COALESCE(role, 'GUEST') as role
|
||||
FROM site_affiliations AS sa
|
||||
) t
|
||||
''')
|
||||
return namedtuplefetchall(cursor)
|
||||
|
||||
def add_old_roles(self):
|
||||
objects = []
|
||||
OldRole.objects.all().delete()
|
||||
for s in tqdm(self.map_role_sql(), desc='Add permissions old'):
|
||||
objects.append(
|
||||
OldRole(new_role=s.new_role, old_role=s.role)
|
||||
)
|
||||
OldRole.objects.bulk_create(objects)
|
||||
self.stdout.write(self.style.WARNING(f'Migrated old roles.'))
|
||||
|
||||
def site_role_sql(self):
|
||||
with connections['legacy'].cursor() as cursor:
|
||||
cursor.execute('''
|
||||
select site_id,
|
||||
role
|
||||
from
|
||||
(
|
||||
SELECT
|
||||
DISTINCT
|
||||
site_id,
|
||||
COALESCE(role, 'GUEST') as role
|
||||
FROM site_affiliations AS sa
|
||||
) t
|
||||
where t.role not in ('admin', 'GUEST')
|
||||
''')
|
||||
return namedtuplefetchall(cursor)
|
||||
|
||||
def add_site_role(self):
|
||||
objects = []
|
||||
for s in tqdm(self.site_role_sql(), desc='Add site role'):
|
||||
old_role = OldRole.objects.get(old_role=s.role)
|
||||
role_choice = getattr(Role, old_role.new_role)
|
||||
sites = SiteSettings.objects.filter(old_id=s.site_id)
|
||||
for site in sites:
|
||||
role = Role.objects.filter(site=site, role=role_choice)
|
||||
if not role.exists():
|
||||
objects.append(
|
||||
Role(site=site, role=role_choice)
|
||||
)
|
||||
|
||||
Role.objects.bulk_create(objects)
|
||||
self.stdout.write(self.style.WARNING(f'Added site roles.'))
|
||||
|
||||
def update_site_role(self):
|
||||
roles = Role.objects.filter(country__isnull=True).select_related('site')\
|
||||
.filter(site__id__isnull=False).select_for_update()
|
||||
with transaction.atomic():
|
||||
for role in tqdm(roles, desc='Update role country'):
|
||||
role.country = role.site.country
|
||||
role.save()
|
||||
self.stdout.write(self.style.WARNING(f'Updated site roles.'))
|
||||
|
||||
def user_role_sql(self):
|
||||
with connections['legacy'].cursor() as cursor:
|
||||
cursor.execute('''
|
||||
select t.*
|
||||
from
|
||||
(
|
||||
SELECT
|
||||
site_id,
|
||||
account_id,
|
||||
COALESCE(role, 'GUEST') as role
|
||||
FROM site_affiliations AS sa
|
||||
) t
|
||||
join accounts a on a.id = t.account_id
|
||||
where t.role not in ('admin', 'GUEST')
|
||||
''')
|
||||
return namedtuplefetchall(cursor)
|
||||
|
||||
def add_role_user(self):
|
||||
for s in tqdm(self.user_role_sql(), desc='Add role to user'):
|
||||
sites = SiteSettings.objects.filter(old_id=s.site_id)
|
||||
old_role = OldRole.objects.get(old_role=s.role)
|
||||
role_choice = getattr(Role, old_role.new_role)
|
||||
roles = Role.objects.filter(site__in=[site for site in sites], role=role_choice)
|
||||
users = User.objects.filter(old_id=s.account_id)
|
||||
for user in users:
|
||||
for role in roles:
|
||||
user_role = UserRole.objects.get_or_create(user=user,
|
||||
role=role)
|
||||
self.stdout.write(self.style.WARNING(f'Added users roles.'))
|
||||
|
||||
def superuser_role_sql(self):
|
||||
with connections['legacy'].cursor() as cursor:
|
||||
cursor.execute('''
|
||||
select t.*
|
||||
from
|
||||
(
|
||||
SELECT
|
||||
site_id,
|
||||
account_id,
|
||||
COALESCE(role, 'GUEST') as role
|
||||
FROM site_affiliations AS sa
|
||||
) t
|
||||
join accounts a on a.id = t.account_id
|
||||
where t.role in ('admin')
|
||||
''')
|
||||
return namedtuplefetchall(cursor)
|
||||
|
||||
def add_superuser(self):
|
||||
for s in tqdm(self.superuser_role_sql(), desc='Add superuser'):
|
||||
users = User.objects.filter(old_id=s.account_id).select_for_update()
|
||||
with transaction.atomic():
|
||||
for user in users:
|
||||
user.is_superuser = True
|
||||
user.save()
|
||||
self.stdout.write(self.style.WARNING(f'Added superuser.'))
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
self.add_old_roles()
|
||||
self.add_site_role()
|
||||
self.update_site_role()
|
||||
self.add_role_user()
|
||||
self.add_superuser()
|
||||
24
apps/account/migrations/0021_oldrole.py
Normal file
24
apps/account/migrations/0021_oldrole.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-03 10:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0020_role_site'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='OldRole',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('new_role', models.CharField(max_length=512, verbose_name='New role')),
|
||||
('old_role', models.CharField(max_length=512, verbose_name='Old role')),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('new_role', 'old_role')},
|
||||
},
|
||||
),
|
||||
]
|
||||
18
apps/account/migrations/0022_auto_20191203_1149.py
Normal file
18
apps/account/migrations/0022_auto_20191203_1149.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-03 11:49
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0021_oldrole'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='oldrole',
|
||||
name='old_role',
|
||||
field=models.CharField(max_length=512, null=True, verbose_name='Old role'),
|
||||
),
|
||||
]
|
||||
22
apps/account/migrations/0023_auto_20191204_0916.py
Normal file
22
apps/account/migrations/0023_auto_20191204_0916.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-04 09:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('account', '0022_auto_20191203_1149'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='role',
|
||||
name='role',
|
||||
field=models.PositiveIntegerField(choices=[(1, 'Standard user'), (2, 'Comments moderator'), (3, 'Country admin'), (4, 'Content page manager'), (5, 'Establishment manager'), (6, 'Reviewer manager'), (7, 'Restaurant reviewer'), (8, 'Sales man'), (9, 'Winery reviewer'), (10, 'Seller')], verbose_name='Role'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='userrole',
|
||||
unique_together={('user', 'role')},
|
||||
),
|
||||
]
|
||||
|
|
@ -32,6 +32,9 @@ class Role(ProjectBaseMixin):
|
|||
ESTABLISHMENT_MANAGER = 5
|
||||
REVIEWER_MANGER = 6
|
||||
RESTAURANT_REVIEWER = 7
|
||||
SALES_MAN = 8
|
||||
WINERY_REVIEWER = 9
|
||||
SELLER = 10
|
||||
|
||||
ROLE_CHOICES = (
|
||||
(STANDARD_USER, 'Standard user'),
|
||||
|
|
@ -40,7 +43,10 @@ class Role(ProjectBaseMixin):
|
|||
(CONTENT_PAGE_MANAGER, 'Content page manager'),
|
||||
(ESTABLISHMENT_MANAGER, 'Establishment manager'),
|
||||
(REVIEWER_MANGER, 'Reviewer manager'),
|
||||
(RESTAURANT_REVIEWER, 'Restaurant reviewer')
|
||||
(RESTAURANT_REVIEWER, 'Restaurant reviewer'),
|
||||
(SALES_MAN, 'Sales man'),
|
||||
(WINERY_REVIEWER, 'Winery reviewer'),
|
||||
(SELLER, 'Seller')
|
||||
)
|
||||
role = models.PositiveIntegerField(verbose_name=_('Role'), choices=ROLE_CHOICES,
|
||||
null=False, blank=False)
|
||||
|
|
@ -293,3 +299,13 @@ class UserRole(ProjectBaseMixin):
|
|||
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)
|
||||
class Meta:
|
||||
unique_together = ['user', 'role']
|
||||
|
||||
|
||||
class OldRole(models.Model):
|
||||
new_role = models.CharField(verbose_name=_('New role'), max_length=512)
|
||||
old_role = models.CharField(verbose_name=_('Old role'), max_length=512, null=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('new_role', 'old_role')
|
||||
|
|
@ -34,7 +34,7 @@ class CheckWhetherBookingAvailable(generics.GenericAPIView):
|
|||
periods = response['periods']
|
||||
periods_by_name = {period['period']: period for period in periods if 'period' in period}
|
||||
if not periods_by_name:
|
||||
return None
|
||||
return response
|
||||
|
||||
period_template = iter(periods_by_name.values()).__next__().copy()
|
||||
period_template.pop('total_left_seats')
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@ class FeatureSerializer(serializers.ModelSerializer):
|
|||
fields = (
|
||||
'id',
|
||||
'slug',
|
||||
'priority'
|
||||
'priority',
|
||||
'route',
|
||||
'site_settings',
|
||||
)
|
||||
|
||||
|
||||
class CurrencySerializer(ProjectModelSerializer):
|
||||
"""Currency serializer."""
|
||||
|
||||
|
|
@ -36,20 +37,24 @@ class CurrencySerializer(ProjectModelSerializer):
|
|||
|
||||
|
||||
class SiteFeatureSerializer(serializers.ModelSerializer):
|
||||
"""Site feature serializer."""
|
||||
id = serializers.IntegerField(source='feature.id')
|
||||
slug = serializers.CharField(source='feature.slug')
|
||||
priority = serializers.IntegerField(source='feature.priority')
|
||||
route = serializers.CharField(source='feature.route.name')
|
||||
source = serializers.IntegerField(source='feature.source')
|
||||
nested = RecursiveFieldSerializer(many=True, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
model = models.SiteFeature
|
||||
fields = (
|
||||
'id',
|
||||
'site_settings',
|
||||
'feature',
|
||||
'published',
|
||||
'main',
|
||||
'nested'
|
||||
)
|
||||
fields = ('main',
|
||||
'id',
|
||||
'slug',
|
||||
'priority',
|
||||
'route',
|
||||
'source',
|
||||
'nested',
|
||||
)
|
||||
|
||||
|
||||
class SiteSettingsSerializer(serializers.ModelSerializer):
|
||||
|
|
@ -95,23 +100,15 @@ class SiteSettingsBackOfficeSerializer(SiteSettingsSerializer):
|
|||
]
|
||||
|
||||
|
||||
class SiteSerializer(serializers.ModelSerializer):
|
||||
class SiteSerializer(SiteSettingsSerializer):
|
||||
country = CountrySerializer()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
model = models.SiteSettings
|
||||
fields = [
|
||||
'subdomain',
|
||||
'site_url',
|
||||
'country',
|
||||
'default_site',
|
||||
'pinterest_page_url',
|
||||
'twitter_page_url',
|
||||
'facebook_page_url',
|
||||
'instagram_page_url',
|
||||
'contact_email',
|
||||
'currency'
|
||||
fields = SiteSettingsSerializer.Meta.fields + [
|
||||
'id',
|
||||
'country'
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -125,30 +122,6 @@ class SiteShortSerializer(serializers.ModelSerializer):
|
|||
]
|
||||
|
||||
|
||||
class SiteBackOfficeSerializer(SiteSerializer):
|
||||
"""Serializer for back office."""
|
||||
|
||||
class Meta(SiteSerializer.Meta):
|
||||
"""Meta class."""
|
||||
fields = SiteSerializer.Meta.fields + [
|
||||
'id',
|
||||
]
|
||||
|
||||
|
||||
class FeatureSerializer(serializers.ModelSerializer):
|
||||
"""Feature serializer."""
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
model = models.Feature
|
||||
fields = (
|
||||
'id',
|
||||
'slug',
|
||||
'priority',
|
||||
'route',
|
||||
'site_settings',
|
||||
)
|
||||
|
||||
|
||||
class AwardBaseSerializer(serializers.ModelSerializer):
|
||||
|
|
|
|||
|
|
@ -61,9 +61,9 @@ class SiteFeatureRUDBackView(generics.RetrieveUpdateDestroyAPIView):
|
|||
|
||||
class SiteSettingsBackOfficeView(SiteSettingsView):
|
||||
"""Site settings View."""
|
||||
serializer_class = serializers.SiteSettingsBackOfficeSerializer
|
||||
serializer_class = serializers.SiteSerializer
|
||||
|
||||
|
||||
class SiteListBackOfficeView(SiteListView):
|
||||
"""Site settings View."""
|
||||
serializer_class = serializers.SiteBackOfficeSerializer
|
||||
serializer_class = serializers.SiteSerializer
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from search_indexes.documents.establishment import EstablishmentDocument
|
||||
from search_indexes.documents.news import NewsDocument
|
||||
from search_indexes.documents.product import ProductDocument
|
||||
from search_indexes.documents.tag_category import TagCategoryDocument
|
||||
from search_indexes.tasks import es_update
|
||||
|
||||
# todo: make signal to update documents on related fields
|
||||
|
|
@ -8,5 +9,6 @@ __all__ = [
|
|||
'EstablishmentDocument',
|
||||
'NewsDocument',
|
||||
'ProductDocument',
|
||||
'TagCategoryDocument',
|
||||
'es_update',
|
||||
]
|
||||
|
|
@ -116,6 +116,7 @@ class EstablishmentDocument(Document):
|
|||
'weekday': fields.IntegerField(attr='weekday'),
|
||||
'weekday_display': fields.KeywordField(attr='get_weekday_display'),
|
||||
'closed_at': fields.KeywordField(attr='closed_at_str'),
|
||||
'opening_at': fields.KeywordField(attr='opening_at_str'),
|
||||
}
|
||||
))
|
||||
address = fields.ObjectField(
|
||||
|
|
|
|||
33
apps/search_indexes/documents/tag_category.py
Normal file
33
apps/search_indexes/documents/tag_category.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
"""Product app documents."""
|
||||
from django.conf import settings
|
||||
from django_elasticsearch_dsl import Document, Index, fields
|
||||
from tag import models
|
||||
|
||||
TagCategoryIndex = Index(settings.ELASTICSEARCH_INDEX_NAMES.get(__name__, 'tag_category'))
|
||||
TagCategoryIndex.settings(number_of_shards=2, number_of_replicas=2)
|
||||
|
||||
|
||||
@TagCategoryIndex.doc_type
|
||||
class TagCategoryDocument(Document):
|
||||
"""TagCategory document."""
|
||||
|
||||
tags = fields.ListField(fields.ObjectField(
|
||||
properties={
|
||||
'id': fields.IntegerField(),
|
||||
'value': fields.KeywordField(),
|
||||
},
|
||||
))
|
||||
|
||||
class Django:
|
||||
model = models.TagCategory
|
||||
fields = (
|
||||
'id',
|
||||
'index_name',
|
||||
'public',
|
||||
'value_type'
|
||||
)
|
||||
related_models = [models.Tag]
|
||||
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().with_base_related()
|
||||
|
|
@ -4,6 +4,8 @@ from django_elasticsearch_dsl_drf.filter_backends import SearchFilterBackend, \
|
|||
FacetedSearchFilterBackend, GeoSpatialFilteringFilterBackend
|
||||
from search_indexes.utils import OBJECT_FIELD_PROPERTIES
|
||||
from six import iteritems
|
||||
from search_indexes.documents import TagCategoryDocument
|
||||
from tag.models import TagCategory
|
||||
|
||||
|
||||
class CustomGeoSpatialFilteringFilterBackend(GeoSpatialFilteringFilterBackend):
|
||||
|
|
@ -21,15 +23,9 @@ class CustomGeoSpatialFilteringFilterBackend(GeoSpatialFilteringFilterBackend):
|
|||
else:
|
||||
result_part = 180 - (180 - first[1] - diff)
|
||||
|
||||
elif second[1] < 0 > first[1]:
|
||||
diff = abs(abs(second[1]) - abs(first[1]))
|
||||
|
||||
if diff > 90:
|
||||
reverse_first, reverse_second = 180 - abs(first[1]), 180 - abs(second[1])
|
||||
result_part = (reverse_first + reverse_second) / 2
|
||||
|
||||
else:
|
||||
result_part = (first[1] + second[1]) / 2
|
||||
elif second[1] < 0 > first[1] or second[1] > 0 < first[1]:
|
||||
reverse_first, reverse_second = 180 - abs(first[1]), 180 - abs(second[1])
|
||||
result_part = ((reverse_first + reverse_second) / 2) * (-1 + (second[1] < 0) * 2)
|
||||
|
||||
else:
|
||||
result_part = (first[1] + second[1]) / 2
|
||||
|
|
@ -62,10 +58,30 @@ class CustomFacetedSearchFilterBackend(FacetedSearchFilterBackend):
|
|||
:param view:
|
||||
:return:
|
||||
"""
|
||||
def makefilter(cur_facet):
|
||||
def myfilter(x):
|
||||
def make_filter(cur_facet):
|
||||
def _filter(x):
|
||||
return cur_facet['facet']._params['field'] != next(iter(x._params))
|
||||
return myfilter
|
||||
return _filter
|
||||
|
||||
def make_tags_filter(cur_facet, tags_to_remove_ids):
|
||||
def _filter(x):
|
||||
if hasattr(x, '_params') and (x._params.get('must') or x._params.get('should')):
|
||||
ret = []
|
||||
for t in ['must', 'should']:
|
||||
terms = x._params.get(t)
|
||||
if terms:
|
||||
for term in terms:
|
||||
if cur_facet['facet']._params['field'] != next(iter(term._params)):
|
||||
return True # different fields. preserve filter
|
||||
else:
|
||||
ret.append(next(iter(term._params.values())) not in tags_to_remove_ids)
|
||||
return all(ret)
|
||||
if cur_facet['facet']._params['field'] != next(iter(x._params)):
|
||||
return True # different fields. preserve filter
|
||||
else:
|
||||
return next(iter(x._params.values())) not in tags_to_remove_ids
|
||||
return _filter
|
||||
|
||||
__facets = self.construct_facets(request, view)
|
||||
setattr(view.paginator, 'facets_computed', {})
|
||||
for __field, __facet in iteritems(__facets):
|
||||
|
|
@ -77,29 +93,73 @@ class CustomFacetedSearchFilterBackend(FacetedSearchFilterBackend):
|
|||
'global'
|
||||
).bucket(__field, agg)
|
||||
else:
|
||||
qs = queryset.__copy__()
|
||||
qs.query = queryset.query._clone()
|
||||
filterer = makefilter(__facet)
|
||||
for param_type in ['must', 'must_not', 'should']:
|
||||
if qs.query._proxied._params.get(param_type):
|
||||
qs.query._proxied._params[param_type] = list(
|
||||
filter(
|
||||
filterer, qs.query._proxied._params[param_type]
|
||||
if __field != 'tag':
|
||||
qs = queryset.__copy__()
|
||||
qs.query = queryset.query._clone()
|
||||
filterer = make_filter(__facet)
|
||||
for param_type in ['must', 'must_not', 'should']:
|
||||
if qs.query._proxied._params.get(param_type):
|
||||
qs.query._proxied._params[param_type] = list(
|
||||
filter(
|
||||
filterer, qs.query._proxied._params[param_type]
|
||||
)
|
||||
)
|
||||
)
|
||||
sh = qs.query._proxied._params.get('should')
|
||||
if (not sh or not len(sh)) \
|
||||
and qs.query._proxied._params.get('minimum_should_match'):
|
||||
qs.query._proxied._params.pop('minimum_should_match')
|
||||
facet_name = '_filter_' + __field
|
||||
qs.aggs.bucket(
|
||||
facet_name,
|
||||
'filter',
|
||||
filter=agg_filter
|
||||
).bucket(__field, agg)
|
||||
view.paginator.facets_computed.update({facet_name: qs.execute().aggregations[facet_name]})
|
||||
sh = qs.query._proxied._params.get('should')
|
||||
if (not sh or not len(sh)) \
|
||||
and qs.query._proxied._params.get('minimum_should_match'):
|
||||
qs.query._proxied._params.pop('minimum_should_match')
|
||||
facet_name = '_filter_' + __field
|
||||
qs.aggs.bucket(
|
||||
facet_name,
|
||||
'filter',
|
||||
filter=agg_filter
|
||||
).bucket(__field, agg)
|
||||
view.paginator.facets_computed.update({facet_name: qs.execute().aggregations[facet_name]})
|
||||
else:
|
||||
tag_facets = []
|
||||
preserve_ids = []
|
||||
facet_name = '_filter_' + __field
|
||||
all_tag_categories = TagCategoryDocument.search() \
|
||||
.filter('term', public=True) \
|
||||
.filter(Q('term', value_type=TagCategory.LIST) | Q('match', index_name='wine-color'))
|
||||
for category in all_tag_categories:
|
||||
tags_to_remove = list(map(lambda t: str(t.id), category.tags))
|
||||
qs = queryset.__copy__()
|
||||
qs.query = queryset.query._clone()
|
||||
filterer = make_tags_filter(__facet, tags_to_remove)
|
||||
for param_type in ['must', 'should']:
|
||||
if qs.query._proxied._params.get(param_type):
|
||||
if qs.query._proxied._params.get(param_type):
|
||||
qs.query._proxied._params[param_type] = list(
|
||||
filter(
|
||||
filterer, qs.query._proxied._params[param_type]
|
||||
)
|
||||
)
|
||||
sh = qs.query._proxied._params.get('should')
|
||||
if (not sh or not len(sh)) \
|
||||
and qs.query._proxied._params.get('minimum_should_match'):
|
||||
qs.query._proxied._params.pop('minimum_should_match')
|
||||
qs.aggs.bucket(
|
||||
facet_name,
|
||||
'filter',
|
||||
filter=agg_filter
|
||||
).bucket(__field, agg)
|
||||
tag_facets.append(qs.execute().aggregations[facet_name])
|
||||
preserve_ids.append(list(map(int, tags_to_remove)))
|
||||
view.paginator.facets_computed.update({facet_name: self.merge_buckets(tag_facets, preserve_ids)})
|
||||
return queryset
|
||||
|
||||
@staticmethod
|
||||
def merge_buckets(buckets: list, preserve_ids: list):
|
||||
"""Reduces all buckets preserving class"""
|
||||
result_bucket = buckets[0]
|
||||
result_bucket.tag.buckets = list(filter(lambda x: x['key'] in preserve_ids[0], result_bucket.tag.buckets._l_))
|
||||
for bucket, ids in list(zip(buckets, preserve_ids))[1:]:
|
||||
for tag in bucket.tag.buckets._l_:
|
||||
if tag['key'] in ids:
|
||||
result_bucket.tag.buckets.append(tag)
|
||||
return result_bucket
|
||||
|
||||
|
||||
class CustomSearchFilterBackend(SearchFilterBackend):
|
||||
"""Custom SearchFilterBackend."""
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ class ScheduleDocumentSerializer(serializers.Serializer):
|
|||
weekday = serializers.IntegerField()
|
||||
weekday_display = serializers.CharField()
|
||||
closed_at = serializers.CharField()
|
||||
opening_at = serializers.CharField()
|
||||
|
||||
|
||||
class InFavoritesMixin(DocumentSerializer):
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ class ProductDocumentViewSet(BaseDocumentViewSet):
|
|||
|
||||
faceted_search_fields = {
|
||||
'tag': {
|
||||
'field': 'wine_colors.id',
|
||||
'field': 'tags.id',
|
||||
'enabled': True,
|
||||
'facet': TermsFacet,
|
||||
'options': {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class Tag(TranslatedFieldsMixin, models.Model):
|
|||
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
|
||||
|
||||
old_id_meta_product = models.PositiveIntegerField(_('old id metadata product'),
|
||||
blank=True, null=True, default=None)
|
||||
blank=True, null=True, default=None)
|
||||
|
||||
objects = TagQuerySet.as_manager()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
"""Tag serializers."""
|
||||
from rest_framework import serializers
|
||||
from establishment.models import (Establishment, EstablishmentType,
|
||||
EstablishmentSubType)
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
|
||||
from establishment.models import (Establishment, EstablishmentType)
|
||||
from news.models import News, NewsType
|
||||
from tag import models
|
||||
from utils.exceptions import (ObjectAlreadyAdded, BindingObjectNotFound,
|
||||
|
|
@ -12,6 +13,9 @@ from utils.serializers import TranslatedField
|
|||
class TagBaseSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for model Tag."""
|
||||
|
||||
def get_extra_kwargs(self):
|
||||
return super().get_extra_kwargs()
|
||||
|
||||
label_translated = TranslatedField()
|
||||
index_name = serializers.CharField(source='value', read_only=True, allow_null=True)
|
||||
|
||||
|
|
@ -37,6 +41,7 @@ class TagBackOfficeSerializer(TagBaseSerializer):
|
|||
'category'
|
||||
)
|
||||
|
||||
|
||||
class TagCategoryProductSerializer(serializers.ModelSerializer):
|
||||
"""SHORT Serializer for TagCategory"""
|
||||
|
||||
|
|
@ -57,7 +62,7 @@ class TagCategoryBaseSerializer(serializers.ModelSerializer):
|
|||
"""Serializer for model TagCategory."""
|
||||
|
||||
label_translated = TranslatedField()
|
||||
tags = TagBaseSerializer(many=True, read_only=True)
|
||||
tags = SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
|
@ -70,6 +75,25 @@ class TagCategoryBaseSerializer(serializers.ModelSerializer):
|
|||
'tags',
|
||||
)
|
||||
|
||||
def get_tags(self, obj):
|
||||
query_params = dict(self.context['request'].query_params)
|
||||
|
||||
if len(query_params) > 1:
|
||||
return []
|
||||
|
||||
params = {}
|
||||
if 'establishment_type' in query_params:
|
||||
params = {
|
||||
'establishments__isnull': False,
|
||||
}
|
||||
elif 'product_type' in query_params:
|
||||
params = {
|
||||
'products__isnull': False,
|
||||
}
|
||||
|
||||
tags = obj.tags.filter(**params).distinct()
|
||||
return TagBaseSerializer(instance=tags, many=True, read_only=True).data
|
||||
|
||||
|
||||
class TagCategoryShortSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for model TagCategory."""
|
||||
|
|
@ -174,15 +198,15 @@ class TagCategoryBindObjectSerializer(serializers.Serializer):
|
|||
attrs['tag_category'] = tag_category
|
||||
|
||||
if obj_type == self.ESTABLISHMENT_TYPE:
|
||||
establishment_type = EstablishmentType.objects.filter(pk=obj_id).\
|
||||
establishment_type = EstablishmentType.objects.filter(pk=obj_id). \
|
||||
first()
|
||||
if not establishment_type:
|
||||
raise BindingObjectNotFound()
|
||||
if request.method == 'POST' and tag_category.establishment_types.\
|
||||
if request.method == 'POST' and tag_category.establishment_types. \
|
||||
filter(pk=establishment_type.pk).exists():
|
||||
raise ObjectAlreadyAdded()
|
||||
if request.method == 'DELETE' and not tag_category.\
|
||||
establishment_types.filter(pk=establishment_type.pk).\
|
||||
if request.method == 'DELETE' and not tag_category. \
|
||||
establishment_types.filter(pk=establishment_type.pk). \
|
||||
exists():
|
||||
raise RemovedBindingObjectNotFound()
|
||||
attrs['related_object'] = establishment_type
|
||||
|
|
@ -190,10 +214,10 @@ class TagCategoryBindObjectSerializer(serializers.Serializer):
|
|||
news_type = NewsType.objects.filter(pk=obj_id).first()
|
||||
if not news_type:
|
||||
raise BindingObjectNotFound()
|
||||
if request.method == 'POST' and tag_category.news_types.\
|
||||
if request.method == 'POST' and tag_category.news_types. \
|
||||
filter(pk=news_type.pk).exists():
|
||||
raise ObjectAlreadyAdded()
|
||||
if request.method == 'DELETE' and not tag_category.news_types.\
|
||||
if request.method == 'DELETE' and not tag_category.news_types. \
|
||||
filter(pk=news_type.pk).exists():
|
||||
raise RemovedBindingObjectNotFound()
|
||||
attrs['related_object'] = news_type
|
||||
|
|
|
|||
|
|
@ -39,6 +39,10 @@ class Timetable(ProjectBaseMixin):
|
|||
def closed_at_str(self):
|
||||
return str(self.closed_at) if self.closed_at else None
|
||||
|
||||
@property
|
||||
def opening_at_str(self):
|
||||
return str(self.opening_at) if self.opening_at else None
|
||||
|
||||
@property
|
||||
def opening_time(self):
|
||||
return self.opening_at or self.lunch_start or self.dinner_start
|
||||
|
|
|
|||
2
fabfile.py
vendored
2
fabfile.py
vendored
|
|
@ -54,7 +54,7 @@ def collectstatic():
|
|||
|
||||
def deploy(branch=None):
|
||||
role = env.roles[0]
|
||||
if env.roledefs[role]['branch'] != 'develop':
|
||||
if env.roledefs[role]['branch'] == 'develop':
|
||||
fetch()
|
||||
install_requirements()
|
||||
migrate()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
./manage.py transfer -a
|
||||
#./manage.py transfer -d
|
||||
./manage.py transfer -d
|
||||
./manage.py transfer -e
|
||||
./manage.py transfer --fill_city_gallery
|
||||
./manage.py transfer -l
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ ELASTICSEARCH_INDEX_NAMES = {
|
|||
'search_indexes.documents.news': 'development_news',
|
||||
'search_indexes.documents.establishment': 'development_establishment',
|
||||
'search_indexes.documents.product': 'development_product',
|
||||
'search_indexes.documents.tag_category': 'development_tag_category',
|
||||
}
|
||||
|
||||
# ELASTICSEARCH_DSL_AUTOSYNC = False
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ ELASTICSEARCH_INDEX_NAMES = {
|
|||
# 'search_indexes.documents.news': 'local_news',
|
||||
'search_indexes.documents.establishment': 'local_establishment',
|
||||
'search_indexes.documents.product': 'local_product',
|
||||
'search_indexes.documents.tag_category': 'local_tag_category',
|
||||
}
|
||||
ELASTICSEARCH_DSL_AUTOSYNC = False
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ ELASTICSEARCH_INDEX_NAMES = {
|
|||
'search_indexes.documents.news': 'development_news', # temporarily disabled
|
||||
'search_indexes.documents.establishment': 'development_establishment',
|
||||
'search_indexes.documents.product': 'development_product',
|
||||
'search_indexes.documents.tag_category': 'development_tag_category',
|
||||
}
|
||||
|
||||
sentry_sdk.init(
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ ELASTICSEARCH_DSL = {
|
|||
ELASTICSEARCH_INDEX_NAMES = {
|
||||
# 'search_indexes.documents.news': 'stage_news', #temporarily disabled
|
||||
'search_indexes.documents.establishment': 'stage_establishment',
|
||||
'search_indexes.documents.tag_category': 'stage_tag_category',
|
||||
}
|
||||
|
||||
COOKIE_DOMAIN = '.id-east.ru'
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user