From 0eb6a73e096632e122f2fa8bcc782a43be44d0f5 Mon Sep 17 00:00:00 2001 From: "a.gorbunov" Date: Fri, 7 Feb 2020 08:44:13 +0000 Subject: [PATCH 1/4] Carousel mixin --- apps/establishment/models.py | 18 ++++++++++++++---- apps/establishment/serializers/back.py | 6 ++++++ apps/news/models.py | 20 +++++++------------- apps/utils/models.py | 16 ++++++++++++++++ 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 60e3e0b5..ec8b57ef 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -33,7 +33,7 @@ from utils.models import ( BaseAttributes, FavoritesMixin, FileMixin, GalleryMixin, HasTagsMixin, IntermediateGalleryModelMixin, ProjectBaseMixin, TJSONField, TranslatedFieldsMixin, TypeDefaultImageMixin, URLImageMixin, default_menu_bool_array, PhoneModelMixin, - AwardsModelMixin) + AwardsModelMixin, CarouselMixin) # todo: establishment type&subtypes check @@ -547,8 +547,14 @@ class EstablishmentQuerySet(models.QuerySet): return self.prefetch_related('menu_set', 'menu_set__plates', 'back_office_wine') -class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, - TranslatedFieldsMixin, HasTagsMixin, FavoritesMixin, AwardsModelMixin): +class Establishment(GalleryMixin, + ProjectBaseMixin, + URLImageMixin, + TranslatedFieldsMixin, + HasTagsMixin, + FavoritesMixin, + AwardsModelMixin, + CarouselMixin): """Establishment model.""" ABANDONED = 0 @@ -717,9 +723,13 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, raise ValidationError('Establishment type of subtype does not match') self.establishment_subtypes.add(establishment_subtype) + @property + def last_review(self): + return self.reviews.by_status(Review.READY).last() + @property def vintage_year(self): - last_review = self.reviews.by_status(Review.READY).last() + last_review = self.last_review if last_review: return last_review.vintage diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 9ac77045..3c218ed0 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -20,6 +20,7 @@ from location.serializers import AddressDetailSerializer, TranslatedField, Addre from main import models as main_models from main.models import Currency from main.serializers import AwardSerializer +from review.serializers import ReviewBaseSerializer from tag.serializers import TagBaseSerializer from utils.decorators import with_base_attributes from utils.methods import string_random @@ -211,6 +212,7 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): subtypes = model_serializers.EstablishmentSubTypeBaseSerializer(source='establishment_subtypes', read_only=True, many=True) type = model_serializers.EstablishmentTypeBaseSerializer(source='establishment_type', read_only=True) + phones = serializers.ListField( source='contact_phones', allow_null=True, @@ -219,8 +221,11 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): required=False, write_only=True, ) + contact_phones = ContactPhonesSerializer(source='phones', read_only=True, many=True) + last_review = ReviewBaseSerializer() + class Meta(model_serializers.EstablishmentBaseSerializer.Meta): fields = [ 'id', @@ -249,6 +254,7 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): 'tags', 'status', 'status_display', + 'last_review', ] def to_representation(self, instance): diff --git a/apps/news/models.py b/apps/news/models.py index e840f9c5..b24d442d 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -22,7 +22,7 @@ from utils.models import ( BaseAttributes, FavoritesMixin, GalleryMixin, HasTagsMixin, IntermediateGalleryModelMixin, ProjectBaseMixin, TJSONField, TranslatedFieldsMixin, TypeDefaultImageMixin, -) + CarouselMixin) from utils.querysets import TranslationQuerysetMixin @@ -257,8 +257,12 @@ class NewsQuerySet(TranslationQuerysetMixin): return self.filter(site__country__code=country_code) if not user.is_superuser else self -class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin, - FavoritesMixin): +class News(GalleryMixin, + BaseAttributes, + TranslatedFieldsMixin, + HasTagsMixin, + FavoritesMixin, + CarouselMixin): """News model.""" STR_FIELD_NAME = 'title' @@ -366,16 +370,6 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin, self.duplication_date = timezone.now() self.save() - @property - def must_of_the_week(self) -> bool: - """Detects whether current item in carousel""" - kwargs = { - 'content_type': ContentType.objects.get_for_model(self), - 'object_id': self.pk, - 'country': self.country, - } - return Carousel.objects.filter(**kwargs).exists() - @property def publication_datetime(self): """Represents datetime object combined from `publication_date` & `publication_time` fields""" diff --git a/apps/utils/models.py b/apps/utils/models.py index 2f2a39d1..06a1bf99 100644 --- a/apps/utils/models.py +++ b/apps/utils/models.py @@ -4,6 +4,7 @@ from os.path import exists from django.conf import settings from django.contrib.auth.tokens import PasswordResetTokenGenerator +from django.contrib.contenttypes.models import ContentType from django.contrib.gis.db import models from django.contrib.postgres.aggregates import ArrayAgg from django.contrib.postgres.fields import JSONField @@ -537,3 +538,18 @@ class AwardsModelMixin: if hasattr(self, 'awards'): self.awards.remove(award) + + +class CarouselMixin: + @property + def must_of_the_week(self) -> bool: + """Detects whether current item in carousel""" + from main.models import Carousel + + if hasattr(self, 'pk') and hasattr(self, 'country'): + kwargs = { + 'content_type': ContentType.objects.get_for_model(self), + 'object_id': self.pk, + 'country': self.country, + } + return Carousel.objects.filter(**kwargs).exists() \ No newline at end of file From 5b6db0f974a04f0d45bc76b0795a14d0d1bbb895 Mon Sep 17 00:00:00 2001 From: "a.gorbunov" Date: Fri, 7 Feb 2020 10:40:30 +0000 Subject: [PATCH 2/4] must of the week mark --- apps/establishment/serializers/back.py | 1 + apps/utils/models.py | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 3c218ed0..cbedea4b 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -255,6 +255,7 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): 'status', 'status_display', 'last_review', + 'must_of_the_week', ] def to_representation(self, instance): diff --git a/apps/utils/models.py b/apps/utils/models.py index 06a1bf99..e61651b2 100644 --- a/apps/utils/models.py +++ b/apps/utils/models.py @@ -518,6 +518,7 @@ def default_menu_bool_array(): class PhoneModelMixin: """Mixin for PhoneNumberField.""" + @cached_property def country_calling_code(self): """Return phone code from PhonеNumberField.""" @@ -546,10 +547,13 @@ class CarouselMixin: """Detects whether current item in carousel""" from main.models import Carousel - if hasattr(self, 'pk') and hasattr(self, 'country'): + if hasattr(self, 'pk') and (hasattr(self, 'country') or hasattr(self, 'country_id')): kwargs = { 'content_type': ContentType.objects.get_for_model(self), 'object_id': self.pk, - 'country': self.country, + 'country': getattr(self, 'country', getattr(self, 'country_id', None)), } - return Carousel.objects.filter(**kwargs).exists() \ No newline at end of file + + return Carousel.objects.filter(**kwargs).exists() + + return False From f854cd6ba57f8d6f77f0b0a988f2d2bc7351ec4c Mon Sep 17 00:00:00 2001 From: "a.gorbunov" Date: Fri, 7 Feb 2020 11:41:49 +0000 Subject: [PATCH 3/4] last update by for establishment --- apps/establishment/models.py | 5 +++-- apps/establishment/serializers/back.py | 31 +++++++++++++++++++++++--- apps/utils/models.py | 11 +++++++++ 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index ec8b57ef..2751987c 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -33,7 +33,7 @@ from utils.models import ( BaseAttributes, FavoritesMixin, FileMixin, GalleryMixin, HasTagsMixin, IntermediateGalleryModelMixin, ProjectBaseMixin, TJSONField, TranslatedFieldsMixin, TypeDefaultImageMixin, URLImageMixin, default_menu_bool_array, PhoneModelMixin, - AwardsModelMixin, CarouselMixin) + AwardsModelMixin, CarouselMixin, UpdateByMixin) # todo: establishment type&subtypes check @@ -554,7 +554,8 @@ class Establishment(GalleryMixin, HasTagsMixin, FavoritesMixin, AwardsModelMixin, - CarouselMixin): + CarouselMixin, + UpdateByMixin): """Establishment model.""" ABANDONED = 0 diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index cbedea4b..311cf028 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -1,3 +1,4 @@ +from datetime import datetime from functools import lru_cache from django.contrib.contenttypes.models import ContentType @@ -9,6 +10,7 @@ from rest_framework import serializers from slugify import slugify from account import models as account_models +from account.models import Role from account.serializers.common import UserShortSerializer from collection.models import Guide from establishment import models, serializers as model_serializers @@ -20,7 +22,7 @@ from location.serializers import AddressDetailSerializer, TranslatedField, Addre from main import models as main_models from main.models import Currency from main.serializers import AwardSerializer -from review.serializers import ReviewBaseSerializer +from review.serializers import ReviewBaseSerializer, User from tag.serializers import TagBaseSerializer from utils.decorators import with_base_attributes from utils.methods import string_random @@ -224,7 +226,7 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): contact_phones = ContactPhonesSerializer(source='phones', read_only=True, many=True) - last_review = ReviewBaseSerializer() + last_review = ReviewBaseSerializer(read_only=True) class Meta(model_serializers.EstablishmentBaseSerializer.Meta): fields = [ @@ -256,6 +258,8 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): 'status_display', 'last_review', 'must_of_the_week', + 'last_update_by_gm', + 'last_update_by_manager', ] def to_representation(self, instance): @@ -263,7 +267,7 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): data['phones'] = data.pop('contact_phones', None) return data - def update(self, instance, validated_data): + def update(self, instance: models.Establishment, validated_data): phones_list = [] if 'contact_phones' in validated_data: phones_list = validated_data.pop('contact_phones') @@ -272,9 +276,30 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): if 'contact_emails' in validated_data: emails_list = validated_data.pop('contact_emails') + request = self.context.get('request') + if request and hasattr(request, 'user'): + user = request.user + + if isinstance(user, User): + is_by_manager = user.userrole_set.filter( + pk=user.pk, + role__in=( + Role.ESTABLISHMENT_MANAGER, + Role.ESTABLISHMENT_ADMINISTRATOR, + Role.COUNTRY_ADMIN + ) + ).exists() + + if is_by_manager: + instance.last_update_by_manager = datetime.now() + else: + ''' by gm. ''' + instance.last_update_by_gm = datetime.now() + instance = super().update(instance, validated_data) phones_handler(phones_list, instance) emails_handler(emails_list, instance) + return instance diff --git a/apps/utils/models.py b/apps/utils/models.py index e61651b2..adbfbbeb 100644 --- a/apps/utils/models.py +++ b/apps/utils/models.py @@ -557,3 +557,14 @@ class CarouselMixin: return Carousel.objects.filter(**kwargs).exists() return False + + +class UpdateByMixin(models.Model): + """Modify by mixin""" + last_update_by_manager = models.DateTimeField(null=True) + + last_update_by_gm = models.DateTimeField(null=True) + + class Meta: + """Meta class.""" + abstract = True From 5023650e8b07e27ea54cc31c8e32d7974de925db Mon Sep 17 00:00:00 2001 From: "a.gorbunov" Date: Fri, 7 Feb 2020 11:43:50 +0000 Subject: [PATCH 4/4] migration for establishment --- .../migrations/0099_auto_20200207_1136.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 apps/establishment/migrations/0099_auto_20200207_1136.py diff --git a/apps/establishment/migrations/0099_auto_20200207_1136.py b/apps/establishment/migrations/0099_auto_20200207_1136.py new file mode 100644 index 00000000..4fac47e8 --- /dev/null +++ b/apps/establishment/migrations/0099_auto_20200207_1136.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.7 on 2020-02-07 11:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0098_auto_20200204_1205'), + ] + + operations = [ + migrations.AddField( + model_name='establishment', + name='last_update_by_gm', + field=models.DateTimeField(null=True), + ), + migrations.AddField( + model_name='establishment', + name='last_update_by_manager', + field=models.DateTimeField(null=True), + ), + ]