Merge branch 'develop' into feature/guides
This commit is contained in:
commit
2401763e6c
|
|
@ -18,7 +18,7 @@ class CollectionViewMixin(generics.GenericAPIView):
|
||||||
"""Override get_queryset method."""
|
"""Override get_queryset method."""
|
||||||
return models.Collection.objects.published() \
|
return models.Collection.objects.published() \
|
||||||
.by_country_code(code=self.request.country_code) \
|
.by_country_code(code=self.request.country_code) \
|
||||||
.order_by('-on_top', '-modified')
|
.order_by('-on_top', '-created')
|
||||||
|
|
||||||
|
|
||||||
class GuideViewMixin(generics.GenericAPIView):
|
class GuideViewMixin(generics.GenericAPIView):
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,13 @@ def determine_country_code(request):
|
||||||
return country_code.lower()
|
return country_code.lower()
|
||||||
|
|
||||||
|
|
||||||
|
def determine_country_name(request):
|
||||||
|
"""Determine country name."""
|
||||||
|
META = request.META
|
||||||
|
return META.get('X-GeoIP-Country-Name',
|
||||||
|
META.get('HTTP_X_GEOIP_COUNTRY_NAME'))
|
||||||
|
|
||||||
|
|
||||||
def determine_coordinates(request):
|
def determine_coordinates(request):
|
||||||
META = request.META
|
META = request.META
|
||||||
longitude = META.get('X-GeoIP-Longitude',
|
longitude = META.get('X-GeoIP-Longitude',
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,25 @@ class CarouselQuerySet(models.QuerySet):
|
||||||
"""Filter collection by country code."""
|
"""Filter collection by country code."""
|
||||||
return self.filter(country__code=code)
|
return self.filter(country__code=code)
|
||||||
|
|
||||||
|
def create_or_destroy(self, instance_to_bind, country):
|
||||||
|
"""Creates or destroys Carousel instance depending on instance fields"""
|
||||||
|
toggle = True
|
||||||
|
kwargs = {
|
||||||
|
'content_type': ContentType.objects.get_for_model(instance_to_bind),
|
||||||
|
'object_id': instance_to_bind.pk,
|
||||||
|
'country': country,
|
||||||
|
}
|
||||||
|
if toggle is None:
|
||||||
|
return
|
||||||
|
elif toggle:
|
||||||
|
kwargs.update({
|
||||||
|
'is_parse': True,
|
||||||
|
'active': True,
|
||||||
|
})
|
||||||
|
self.create(**kwargs)
|
||||||
|
else:
|
||||||
|
self.filter(**kwargs).delete()
|
||||||
|
|
||||||
|
|
||||||
class Carousel(models.Model):
|
class Carousel(models.Model):
|
||||||
"""Carousel model."""
|
"""Carousel model."""
|
||||||
|
|
@ -279,6 +298,11 @@ class Carousel(models.Model):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def slug(self):
|
def slug(self):
|
||||||
|
if hasattr(self.content_object, 'slugs'):
|
||||||
|
try:
|
||||||
|
return next(iter(self.content_object.slugs.values()))
|
||||||
|
except StopIteration:
|
||||||
|
return None
|
||||||
if hasattr(self.content_object, 'slug'):
|
if hasattr(self.content_object, 'slug'):
|
||||||
return self.content_object.slug
|
return self.content_object.slug
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,9 @@ class DetermineLocation(generics.GenericAPIView):
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
longitude, latitude = methods.determine_coordinates(request)
|
longitude, latitude = methods.determine_coordinates(request)
|
||||||
city = methods.determine_user_city(request)
|
city = methods.determine_user_city(request)
|
||||||
if longitude and latitude and city:
|
country_name = methods.determine_country_name(request)
|
||||||
return Response(data={'latitude': latitude, 'longitude': longitude, 'city': city})
|
if longitude and latitude and city and country_name:
|
||||||
else:
|
return Response(data={'latitude': latitude, 'longitude': longitude,
|
||||||
|
'city': city, 'country_name': country_name})
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
|
|
|
||||||
18
apps/news/migrations/0045_news_must_of_the_week.py
Normal file
18
apps/news/migrations/0045_news_must_of_the_week.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 2.2.7 on 2019-12-17 17:59
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('news', '0044_auto_20191216_2044'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='news',
|
||||||
|
name='must_of_the_week',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -223,6 +223,7 @@ class News(GalleryModelMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixi
|
||||||
verbose_name=_('Duplication datetime'))
|
verbose_name=_('Duplication datetime'))
|
||||||
duplication_uuid = models.UUIDField(default=uuid.uuid4, editable=True, unique=False,
|
duplication_uuid = models.UUIDField(default=uuid.uuid4, editable=True, unique=False,
|
||||||
verbose_name=_('Field to detect doubles'))
|
verbose_name=_('Field to detect doubles'))
|
||||||
|
must_of_the_week = models.BooleanField(default=False, verbose_name=_('Show in the carousel'))
|
||||||
objects = NewsQuerySet.as_manager()
|
objects = NewsQuerySet.as_manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -248,6 +249,11 @@ class News(GalleryModelMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixi
|
||||||
"""Duplicates for this news item excluding same country code labeled"""
|
"""Duplicates for this news item excluding same country code labeled"""
|
||||||
return News.objects.filter(duplication_uuid=self.duplication_uuid).exclude(country=self.country)
|
return News.objects.filter(duplication_uuid=self.duplication_uuid).exclude(country=self.country)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_any_desc_active(self):
|
||||||
|
"""Detects whether news item has any active description"""
|
||||||
|
return any(list(map(lambda v: v.lower() == 'true', self.locale_to_description_is_active.values())))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_publish(self):
|
def is_publish(self):
|
||||||
return self.state in self.PUBLISHED_STATES
|
return self.state in self.PUBLISHED_STATES
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from rest_framework.fields import SerializerMethodField
|
||||||
|
|
||||||
from account.serializers.common import UserBaseSerializer
|
from account.serializers.common import UserBaseSerializer
|
||||||
from gallery.models import Image
|
from gallery.models import Image
|
||||||
from main.models import SiteSettings
|
from main.models import SiteSettings, Carousel
|
||||||
from location import models as location_models
|
from location import models as location_models
|
||||||
from location.serializers import CountrySimpleSerializer, AddressBaseSerializer
|
from location.serializers import CountrySimpleSerializer, AddressBaseSerializer
|
||||||
from news import models
|
from news import models
|
||||||
|
|
@ -185,6 +185,7 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer):
|
||||||
'locale_to_description_is_active',
|
'locale_to_description_is_active',
|
||||||
'is_published',
|
'is_published',
|
||||||
'duplication_date',
|
'duplication_date',
|
||||||
|
'must_of_the_week',
|
||||||
)
|
)
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'backoffice_title': {'allow_null': False},
|
'backoffice_title': {'allow_null': False},
|
||||||
|
|
@ -199,7 +200,9 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer):
|
||||||
slugs__values__contains=list(slugs.values())
|
slugs__values__contains=list(slugs.values())
|
||||||
).exists():
|
).exists():
|
||||||
raise serializers.ValidationError({'slugs': _('News with this slug already exists.')})
|
raise serializers.ValidationError({'slugs': _('News with this slug already exists.')})
|
||||||
return super().create(validated_data)
|
instance = super().create(validated_data)
|
||||||
|
Carousel.objects.create_or_destroy(instance, instance.address.city.country)
|
||||||
|
return instance
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
slugs = validated_data.get('slugs')
|
slugs = validated_data.get('slugs')
|
||||||
|
|
@ -208,7 +211,10 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer):
|
||||||
slugs__values__contains=list(slugs.values())
|
slugs__values__contains=list(slugs.values())
|
||||||
).exclude(pk=instance.pk).exists():
|
).exclude(pk=instance.pk).exists():
|
||||||
raise serializers.ValidationError({'slugs': _('News with this slug already exists.')})
|
raise serializers.ValidationError({'slugs': _('News with this slug already exists.')})
|
||||||
return super().update(instance, validated_data)
|
ret = super().update(instance, validated_data)
|
||||||
|
if ret.must_of_the_week != instance.must_of_the_week:
|
||||||
|
Carousel.objects.create_or_destroy(instance, instance.address.city.country)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class NewsBackOfficeDuplicationInfoSerializer(serializers.ModelSerializer):
|
class NewsBackOfficeDuplicationInfoSerializer(serializers.ModelSerializer):
|
||||||
|
|
@ -380,5 +386,5 @@ class NewsCloneCreateSerializer(NewsBackOfficeBaseSerializer,
|
||||||
new_country = get_object_or_404(location_models.Country, code=kwargs['country_code'])
|
new_country = get_object_or_404(location_models.Country, code=kwargs['country_code'])
|
||||||
view_count_model = rating_models.ViewCount.objects.create(count=0)
|
view_count_model = rating_models.ViewCount.objects.create(count=0)
|
||||||
instance.create_duplicate(new_country, view_count_model)
|
instance.create_duplicate(new_country, view_count_model)
|
||||||
return instance
|
return get_object_or_404(models.News, pk=kwargs['pk'])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,8 @@ class NewsListView(NewsMixinView, generics.ListAPIView):
|
||||||
'international_preferred': True,
|
'international_preferred': True,
|
||||||
'locale': locale,
|
'locale': locale,
|
||||||
})
|
})
|
||||||
return super().get_queryset(*args, **kwargs)
|
return super().get_queryset(*args, **kwargs)\
|
||||||
|
.filter(locale_to_description_is_active__values__contains=['True'])
|
||||||
|
|
||||||
|
|
||||||
class NewsDetailView(NewsMixinView, generics.RetrieveAPIView):
|
class NewsDetailView(NewsMixinView, generics.RetrieveAPIView):
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ from django.conf import settings
|
||||||
from django_elasticsearch_dsl import Document, Index, fields
|
from django_elasticsearch_dsl import Document, Index, fields
|
||||||
from search_indexes.utils import OBJECT_FIELD_PROPERTIES
|
from search_indexes.utils import OBJECT_FIELD_PROPERTIES
|
||||||
from news import models
|
from news import models
|
||||||
|
from json import dumps
|
||||||
|
|
||||||
|
|
||||||
NewsIndex = Index(settings.ELASTICSEARCH_INDEX_NAMES.get(__name__, 'news'))
|
NewsIndex = Index(settings.ELASTICSEARCH_INDEX_NAMES.get(__name__, 'news'))
|
||||||
|
|
@ -17,7 +18,7 @@ class NewsDocument(Document):
|
||||||
'name': fields.KeywordField()})
|
'name': fields.KeywordField()})
|
||||||
title = fields.ObjectField(attr='title_indexing',
|
title = fields.ObjectField(attr='title_indexing',
|
||||||
properties=OBJECT_FIELD_PROPERTIES)
|
properties=OBJECT_FIELD_PROPERTIES)
|
||||||
slugs = fields.ObjectField(properties=OBJECT_FIELD_PROPERTIES)
|
slugs = fields.KeywordField()
|
||||||
backoffice_title = fields.TextField(analyzer='english')
|
backoffice_title = fields.TextField(analyzer='english')
|
||||||
subtitle = fields.ObjectField(attr='subtitle_indexing',
|
subtitle = fields.ObjectField(attr='subtitle_indexing',
|
||||||
properties=OBJECT_FIELD_PROPERTIES)
|
properties=OBJECT_FIELD_PROPERTIES)
|
||||||
|
|
@ -45,9 +46,10 @@ class NewsDocument(Document):
|
||||||
multi=True)
|
multi=True)
|
||||||
favorites_for_users = fields.ListField(field=fields.IntegerField())
|
favorites_for_users = fields.ListField(field=fields.IntegerField())
|
||||||
start = fields.DateField(attr='start')
|
start = fields.DateField(attr='start')
|
||||||
|
has_any_desc_active = fields.BooleanField()
|
||||||
|
|
||||||
def prepare_slugs(self, instance):
|
def prepare_slugs(self, instance):
|
||||||
return {locale: instance.slugs.get(locale) for locale in OBJECT_FIELD_PROPERTIES}
|
return dumps(instance.slugs or {})
|
||||||
|
|
||||||
class Django:
|
class Django:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from news.serializers import NewsTypeSerializer
|
||||||
from search_indexes.documents import EstablishmentDocument, NewsDocument
|
from search_indexes.documents import EstablishmentDocument, NewsDocument
|
||||||
from search_indexes.documents.product import ProductDocument
|
from search_indexes.documents.product import ProductDocument
|
||||||
from search_indexes.utils import get_translated_value
|
from search_indexes.utils import get_translated_value
|
||||||
|
from json import loads
|
||||||
|
|
||||||
|
|
||||||
class TagsDocumentSerializer(serializers.Serializer):
|
class TagsDocumentSerializer(serializers.Serializer):
|
||||||
|
|
@ -243,7 +244,7 @@ class NewsDocumentSerializer(InFavoritesMixin, DocumentSerializer):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_slug(obj):
|
def get_slug(obj):
|
||||||
return get_translated_value(obj.slugs)
|
return get_translated_value(loads(obj.slugs))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_title_translated(obj):
|
def get_title_translated(obj):
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,11 @@ from utils.pagination import ESDocumentPagination
|
||||||
class NewsDocumentViewSet(BaseDocumentViewSet):
|
class NewsDocumentViewSet(BaseDocumentViewSet):
|
||||||
"""News document ViewSet."""
|
"""News document ViewSet."""
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
qs = super(NewsDocumentViewSet, self).get_queryset()
|
||||||
|
qs = qs.filter('match', has_any_desc_active=True)
|
||||||
|
return qs
|
||||||
|
|
||||||
document = NewsDocument
|
document = NewsDocument
|
||||||
lookup_field = 'slug'
|
lookup_field = 'slug'
|
||||||
pagination_class = ESDocumentPagination
|
pagination_class = ESDocumentPagination
|
||||||
|
|
|
||||||
|
|
@ -67,16 +67,23 @@ def get_default_locale():
|
||||||
settings.FALLBACK_LOCALE
|
settings.FALLBACK_LOCALE
|
||||||
|
|
||||||
|
|
||||||
def translate_field(self, field_name):
|
def translate_field(self, field_name, toggle_field_name=None):
|
||||||
def translate(self):
|
def translate(self):
|
||||||
field = getattr(self, field_name)
|
field = getattr(self, field_name)
|
||||||
|
toggler = getattr(self, toggle_field_name, None)
|
||||||
if isinstance(field, dict):
|
if isinstance(field, dict):
|
||||||
|
if toggler:
|
||||||
|
field = {locale: v for locale, v in field.items() if toggler.get(locale) in [True, 'True', 'true']}
|
||||||
value = field.get(to_locale(get_language()))
|
value = field.get(to_locale(get_language()))
|
||||||
# fallback
|
# fallback
|
||||||
if value is None:
|
if value is None:
|
||||||
value = field.get(get_default_locale())
|
value = field.get(get_default_locale())
|
||||||
if value is None:
|
if value is None:
|
||||||
value = field.get(next(iter(field.keys()), None))
|
try:
|
||||||
|
value = next(iter(field.values()))
|
||||||
|
except StopIteration:
|
||||||
|
# field values are absent
|
||||||
|
return None
|
||||||
return value
|
return value
|
||||||
return None
|
return None
|
||||||
return translate
|
return translate
|
||||||
|
|
@ -114,7 +121,7 @@ class TranslatedFieldsMixin:
|
||||||
field_name = field.name
|
field_name = field.name
|
||||||
if isinstance(field, TJSONField):
|
if isinstance(field, TJSONField):
|
||||||
setattr(cls, f'{field.name}_translated',
|
setattr(cls, f'{field.name}_translated',
|
||||||
property(translate_field(self, field_name)))
|
property(translate_field(self, field_name, f'locale_to_{field_name}_is_active')))
|
||||||
setattr(cls, f'{field_name}_indexing',
|
setattr(cls, f'{field_name}_indexing',
|
||||||
property(index_field(self, field_name)))
|
property(index_field(self, field_name)))
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user