Merge branch 'develop' into feature/guides

This commit is contained in:
Anatoly 2019-12-25 22:16:48 +03:00
commit cbe03b2f5a
8 changed files with 185 additions and 6 deletions

View File

@ -191,7 +191,7 @@ def update_fake_country_flag():
resp = get(link_to_request) resp = get(link_to_request)
if resp.status_code == 200: if resp.status_code == 200:
country = Country.objects.get(code="aa") country = Country.objects.get(code="aa")
country.svg_image = link_to_request country.svg_image = "/svg/country/10-31-2019/aa.svg"
country.save() country.save()

View File

@ -283,7 +283,7 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin,
@property @property
def has_any_desc_active(self): def has_any_desc_active(self):
"""Detects whether news item has any active description""" """Detects whether news item has any active description"""
return any(list(map(lambda v: v.lower() == 'true', self.locale_to_description_is_active.values()))) return any(list(map(lambda v: v.lower() == 'true' if isinstance(v, str) else v, self.locale_to_description_is_active.values())))
@property @property
def is_publish(self): def is_publish(self):
@ -307,7 +307,7 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin,
def main_image(self): def main_image(self):
qs = self.news_gallery.main_image() qs = self.news_gallery.main_image()
if qs.exists(): if qs.exists():
return qs.first().image return qs.order_by('-id').first().image
@property @property
def image_url(self): def image_url(self):
@ -367,6 +367,17 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin,
{f'{crop[len(f"{model_name}_"):]}_url': image.get_image_url(crop)}) {f'{crop[len(f"{model_name}_"):]}_url': image.get_image_url(crop)})
return image_property return image_property
@property
def descriptions(self):
"""Read-only list field for backoffice news representation"""
return [{
'locale': locale,
'slug': (self.slugs or {}).get(locale),
'status': 'active' if (self.locale_to_description_is_active or {}).get(locale) else 'inactive',
'title': (self.title or {}).get(locale),
'text': desc
} for locale, desc in self.description.items()] if self.description else []
class NewsGallery(IntermediateGalleryModelMixin): class NewsGallery(IntermediateGalleryModelMixin):
news = models.ForeignKey(News, null=True, news = models.ForeignKey(News, null=True,

View File

@ -178,6 +178,7 @@ class NewsDetailWebSerializer(NewsDetailSerializer):
class NewsBackOfficeBaseSerializer(NewsBaseSerializer): class NewsBackOfficeBaseSerializer(NewsBaseSerializer):
"""News back office base serializer.""" """News back office base serializer."""
is_published = serializers.BooleanField(source='is_publish', read_only=True) is_published = serializers.BooleanField(source='is_publish', read_only=True)
descriptions = serializers.ListField(required=False)
class Meta(NewsBaseSerializer.Meta): class Meta(NewsBaseSerializer.Meta):
"""Meta class.""" """Meta class."""
@ -195,6 +196,7 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer):
'publication_time', 'publication_time',
'created', 'created',
'modified', 'modified',
'descriptions',
) )
extra_kwargs = { extra_kwargs = {
'created': {'read_only': True}, 'created': {'read_only': True},
@ -204,6 +206,22 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer):
'must_of_the_week': {'read_only': True}, 'must_of_the_week': {'read_only': True},
} }
def validate(self, attrs):
"""Overridden validate method."""
if 'descriptions' in attrs:
descriptions = attrs.pop('descriptions')
status_to_bool = {
'active': True,
'inactive': False,
}
attrs['slugs'] = {obj['locale']: obj['slug'] for obj in descriptions}
attrs['title'] = {obj['locale']: obj['title'] for obj in descriptions}
attrs['locale_to_description_is_active'] = {
obj['locale']: status_to_bool[obj['status']] for obj in descriptions
}
attrs['description'] = {obj['locale']: obj['text'] for obj in descriptions}
return attrs
def create(self, validated_data): def create(self, validated_data):
slugs = validated_data.get('slugs') slugs = validated_data.get('slugs')

View File

@ -1,7 +1,8 @@
"""Admin page for app Review""" """Admin page for app Review"""
from . import models
from django.contrib import admin from django.contrib import admin
from utils.admin import BaseModelAdminMixin from utils.admin import BaseModelAdminMixin
from . import models
@admin.register(models.Review) @admin.register(models.Review)
@ -9,3 +10,11 @@ class ReviewAdminModel(BaseModelAdminMixin, admin.ModelAdmin):
"""Admin model for model Review.""" """Admin model for model Review."""
raw_id_fields = ('reviewer', 'child', 'country') raw_id_fields = ('reviewer', 'child', 'country')
@admin.register(models.ReviewTextAuthor)
class ReviewTextAuthorAdminModel(BaseModelAdminMixin, admin.ModelAdmin):
"""Admin model for model ReviewTextAuthor."""
list_display = ('author', 'review', 'locale', 'modified')
raw_id_fields = ('author', 'review')

View File

@ -0,0 +1,33 @@
# Generated by Django 2.2.7 on 2019-12-24 08:30
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('review', '0019_review_priority'),
]
operations = [
migrations.CreateModel(
name='ReviewTextAuthor',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')),
('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
('locale', models.CharField(max_length=10, verbose_name='locale')),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='review_authors', to=settings.AUTH_USER_MODEL, verbose_name='author')),
('review', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='text_authors', to='review.Review', verbose_name='review')),
],
options={
'verbose_name': 'Text author',
'verbose_name_plural': 'Text authors',
'unique_together': {('locale', 'review')},
},
),
]

View File

@ -1,7 +1,11 @@
"""Review app models.""" """Review app models."""
from pprint import pprint
from django.contrib.contenttypes import fields as generic from django.contrib.contenttypes import fields as generic
from django.core.validators import MinValueValidator, MaxValueValidator from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models from django.db import models
from django.db.models.signals import post_init, post_save
from django.dispatch import receiver
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from utils.models import (BaseAttributes, TranslatedFieldsMixin, from utils.models import (BaseAttributes, TranslatedFieldsMixin,
@ -93,6 +97,27 @@ class Review(BaseAttributes, TranslatedFieldsMixin):
verbose_name_plural = _('Reviews') verbose_name_plural = _('Reviews')
class ReviewTextAuthor(ProjectBaseMixin):
author = models.ForeignKey(
'account.User',
verbose_name=_('author'),
on_delete=models.CASCADE,
related_name='review_authors',
)
review = models.ForeignKey(
'review.Review',
verbose_name=_('review'),
on_delete=models.CASCADE,
related_name='text_authors',
)
locale = models.CharField(_('locale'), max_length=10)
class Meta:
verbose_name = _('Text author')
verbose_name_plural = _('Text authors')
unique_together = ('locale', 'review')
class Inquiries(GalleryMixin, ProjectBaseMixin): class Inquiries(GalleryMixin, ProjectBaseMixin):
NONE = 0 NONE = 0
DINER = 1 DINER = 1

View File

@ -1,9 +1,10 @@
"""Review app back serializers.""" """Review app back serializers."""
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from rest_framework import serializers from rest_framework import serializers
from account.models import User from account.models import User
from review.models import Review from review.models import Review, ReviewTextAuthor
class _ReviewerSerializer(serializers.ModelSerializer): class _ReviewerSerializer(serializers.ModelSerializer):
@ -28,10 +29,24 @@ class _ContentTypeSerializer(serializers.ModelSerializer):
) )
class _ReviewTextAuthorSerializer(serializers.ModelSerializer):
author = _ReviewerSerializer(read_only=True)
class Meta:
model = ReviewTextAuthor
fields = (
'id',
'author',
'locale',
'modified',
)
class ReviewBackSerializer(serializers.ModelSerializer): class ReviewBackSerializer(serializers.ModelSerializer):
reviewer_data = _ReviewerSerializer(read_only=True, source='reviewer') reviewer_data = _ReviewerSerializer(read_only=True, source='reviewer')
content_type_data = _ContentTypeSerializer(read_only=True, source='content_type') content_type_data = _ContentTypeSerializer(read_only=True, source='content_type')
status_display = serializers.CharField(read_only=True, source='get_status_display') status_display = serializers.CharField(read_only=True, source='get_status_display')
authors = _ReviewTextAuthorSerializer(read_only=True, many=True, source='text_authors')
class Meta: class Meta:
model = Review model = Review
@ -51,4 +66,72 @@ class ReviewBackSerializer(serializers.ModelSerializer):
'content_type', 'content_type',
'content_type_data', 'content_type_data',
'object_id', 'object_id',
'authors',
) )
def update(self, instance, validated_data):
old_text = instance.text
new_text = validated_data['text']
# если поле text не менялось - то ничего не делаем
if new_text == old_text:
return super().update(instance, validated_data)
# если пользователь анонимный - то ничего не делаем
user = self.context['request'].user
if user.is_anonymous:
return super().update(instance, validated_data)
for locale, text in new_text.items():
# если поменяли имеющийся текст
if locale in old_text and text != old_text[locale]:
review_author, _ = ReviewTextAuthor.objects.update_or_create(
review=instance,
locale=locale,
defaults={
'author': user,
}
)
# если добавили новый перевод
elif locale not in old_text:
ReviewTextAuthor.objects.create(
author=user,
review=instance,
locale=locale,
)
for locale in old_text:
# Если удалили перевод
if locale not in new_text:
ReviewTextAuthor.objects.filter(
author=user,
review=instance,
locale=locale,
).delete()
return super().update(instance, validated_data)
def create(self, validated_data):
obj = super().create(validated_data)
new_text = validated_data['text']
# если нет переводов для review - то ничего не делаем
if not isinstance(new_text, dict):
return obj
# если пользователь анонимный - то ничего не делаем
user = self.context['request'].user
if user.is_anonymous:
return obj
for locale, text in new_text.items():
ReviewTextAuthor.objects.create(
author=user,
review=obj,
locale=locale,
)
return obj

View File

@ -73,7 +73,7 @@ class TagsFilterSet(TagsBaseFilterSet):
def by_establishment_type(self, queryset, name, value): def by_establishment_type(self, queryset, name, value):
if value == EstablishmentType.ARTISAN: if value == EstablishmentType.ARTISAN:
qs = models.Tag.objects.filter(index_name__in=settings.ARTISANS_CHOSEN_TAGS) qs = models.Tag.objects.filter(value__in=settings.ARTISANS_CHOSEN_TAGS)
if self.request.country_code and self.request.country_code not in settings.INTERNATIONAL_COUNTRY_CODES: if self.request.country_code and self.request.country_code not in settings.INTERNATIONAL_COUNTRY_CODES:
qs = qs.filter(establishments__address__city__country__code=self.request.country_code).distinct('id') qs = qs.filter(establishments__address__city__country__code=self.request.country_code).distinct('id')
return qs.exclude(establishments__isnull=True) return qs.exclude(establishments__isnull=True)