From 84fb0aec705882245f65ccbeff84324cdb4f92be Mon Sep 17 00:00:00 2001 From: Anatoly Date: Thu, 24 Oct 2019 16:41:41 +0300 Subject: [PATCH 1/4] change field parameter in model Guide (gm-241) --- .../migrations/0016_auto_20191024_1334.py | 19 +++++++++++++++++++ apps/collection/models.py | 5 +++-- apps/news/models.py | 6 ++++-- apps/news/serializers.py | 2 +- 4 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 apps/collection/migrations/0016_auto_20191024_1334.py diff --git a/apps/collection/migrations/0016_auto_20191024_1334.py b/apps/collection/migrations/0016_auto_20191024_1334.py new file mode 100644 index 00000000..a362777f --- /dev/null +++ b/apps/collection/migrations/0016_auto_20191024_1334.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.4 on 2019-10-24 13:34 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('collection', '0015_auto_20191023_0715'), + ] + + operations = [ + migrations.AlterField( + model_name='guide', + name='collection', + field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='collection.Collection', verbose_name='collection'), + ), + ] diff --git a/apps/collection/models.py b/apps/collection/models.py index 0a2700bd..cbcc3842 100644 --- a/apps/collection/models.py +++ b/apps/collection/models.py @@ -101,8 +101,9 @@ class Guide(ProjectBaseMixin, CollectionNameMixin, CollectionDateMixin): advertorials = JSONField( _('advertorials'), null=True, blank=True, default=None, help_text='{"key":"value"}') - collection = models.ForeignKey( - Collection, verbose_name=_('collection'), on_delete=models.CASCADE) + collection = models.ForeignKey(Collection, on_delete=models.CASCADE, + null=True, blank=True, default=None, + verbose_name=_('collection')) objects = GuideQuerySet.as_manager() diff --git a/apps/news/models.py b/apps/news/models.py index a2130fac..d7bad867 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -194,13 +194,15 @@ class News(BaseAttributes, TranslatedFieldsMixin): @property def main_image(self): - return self.news_gallery.main_images().first().image + qs = self.news_gallery.main_image() + if qs.exists(): + return qs.first().image class NewsGalleryQuerySet(models.QuerySet): """QuerySet for model News""" - def main_images(self): + def main_image(self): """Return objects with flag is_main is True""" return self.filter(is_main=True) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 31c8fc91..2b4e98b6 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -281,7 +281,7 @@ class NewsBackOfficeGallerySerializer(serializers.ModelSerializer): if news.news_gallery.filter(image=image).exists(): raise serializers.ValidationError({'detail': _('Image is already added')}) - if is_main and news.news_gallery.main_images().exists(): + if is_main and news.news_gallery.main_image().exists(): raise serializers.ValidationError({'detail': _('Main image is already added')}) attrs['news'] = news From 2864576c0c8b988c9356083fb0eb56711a126c35 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Thu, 24 Oct 2019 17:09:08 +0300 Subject: [PATCH 2/4] fix TimeZoneChoiceField --- apps/utils/serializers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/utils/serializers.py b/apps/utils/serializers.py index a2a33ee2..eeff1043 100644 --- a/apps/utils/serializers.py +++ b/apps/utils/serializers.py @@ -58,7 +58,11 @@ class TimeZoneChoiceField(serializers.ChoiceField): super().__init__(choices=choices, **kwargs) def to_representation(self, value): - return value.zone + if isinstance(value, str): + return value + elif isinstance(value, pytz.tzinfo.BaseTzInfo): + return value.zone + return None def to_internal_value(self, data): return pytz.timezone(data) From 81cdaa5c89d221428f842f0c70d4173e2ea8ea88 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Thu, 24 Oct 2019 19:53:09 +0300 Subject: [PATCH 3/4] added image_url & preview_image_url to NewsDocument --- .../migrations/0028_auto_20191024_1649.py | 28 +++++++++++++++++++ apps/news/models.py | 14 ++++++++-- apps/search_indexes/documents/news.py | 2 ++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 apps/news/migrations/0028_auto_20191024_1649.py diff --git a/apps/news/migrations/0028_auto_20191024_1649.py b/apps/news/migrations/0028_auto_20191024_1649.py new file mode 100644 index 00000000..c9eaacb1 --- /dev/null +++ b/apps/news/migrations/0028_auto_20191024_1649.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2.4 on 2019-10-24 16:49 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0027_remove_news_playlist'), + ] + + operations = [ + migrations.AlterField( + model_name='newsgallery', + name='image', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='news_gallery', to='gallery.Image', verbose_name='gallery'), + ), + migrations.AlterField( + model_name='newsgallery', + name='news', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='news_gallery', to='news.News', verbose_name='news'), + ), + migrations.AlterUniqueTogether( + name='newsgallery', + unique_together={('news', 'is_main')}, + ), + ] diff --git a/apps/news/models.py b/apps/news/models.py index d7bad867..dbb2f5bf 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -198,6 +198,15 @@ class News(BaseAttributes, TranslatedFieldsMixin): if qs.exists(): return qs.first().image + @property + def image_url(self): + return self.main_image.image.url if self.main_image else None + + @property + def preview_image_url(self): + if self.main_image: + return self.main_image.get_image_url(thumbnail_key='news_preview') + class NewsGalleryQuerySet(models.QuerySet): """QuerySet for model News""" @@ -211,11 +220,11 @@ class NewsGallery(models.Model): news = models.ForeignKey(News, null=True, related_name='news_gallery', - on_delete=models.SET_NULL, + on_delete=models.CASCADE, verbose_name=_('news')) image = models.ForeignKey('gallery.Image', null=True, related_name='news_gallery', - on_delete=models.SET_NULL, + on_delete=models.CASCADE, verbose_name=_('gallery')) is_main = models.BooleanField(default=False, verbose_name=_('Is the main image')) @@ -226,3 +235,4 @@ class NewsGallery(models.Model): """NewsGallery meta class.""" verbose_name = _('news gallery') verbose_name_plural = _('news galleries') + unique_together = ('news', 'is_main') diff --git a/apps/search_indexes/documents/news.py b/apps/search_indexes/documents/news.py index 699a1cca..86b117e5 100644 --- a/apps/search_indexes/documents/news.py +++ b/apps/search_indexes/documents/news.py @@ -24,6 +24,8 @@ class NewsDocument(Document): country = fields.ObjectField(properties={'id': fields.IntegerField(), 'code': fields.KeywordField()}) web_url = fields.KeywordField(attr='web_url') + image_url = fields.KeywordField(attr='image_url') + preview_image_url = fields.KeywordField(attr='preview_image_url') tags = fields.ObjectField( properties={ 'id': fields.IntegerField(attr='id'), From 66ddfb455b032f5da8433a02e4ffa51b6134c9c0 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Thu, 24 Oct 2019 22:19:59 +0300 Subject: [PATCH 4/4] fix tests --- apps/establishment/tests.py | 4 +- apps/favorites/tests.py | 71 ++++++++++++++++++---------- apps/news/tests.py | 35 ++++++++------ apps/news/urls/back.py | 2 +- apps/news/views.py | 27 +++++++---- apps/utils/tests/tests_translated.py | 5 +- docker-compose.yml | 8 ---- project/settings/local.py | 5 -- 8 files changed, 91 insertions(+), 66 deletions(-) diff --git a/apps/establishment/tests.py b/apps/establishment/tests.py index a1d8fcb5..43aa62c6 100644 --- a/apps/establishment/tests.py +++ b/apps/establishment/tests.py @@ -9,6 +9,7 @@ from establishment.models import Establishment, EstablishmentType, Menu from translation.models import Language from account.models import Role, UserRole from location.models import Country, Address, City, Region +from pytz import timezone as py_tz class BaseTestCase(APITestCase): @@ -77,7 +78,8 @@ class EstablishmentBTests(BaseTestCase): 'name': 'Test establishment', 'type_id': self.establishment_type.id, 'is_publish': True, - 'slug': 'test-establishment-slug' + 'slug': 'test-establishment-slug', + 'tz': py_tz('Europe/Moscow').zone } response = self.client.post('/api/back/establishments/', data=data, format='json') diff --git a/apps/favorites/tests.py b/apps/favorites/tests.py index dd5c6c4f..cebd43c2 100644 --- a/apps/favorites/tests.py +++ b/apps/favorites/tests.py @@ -1,14 +1,16 @@ # Create your tests here. from http.cookies import SimpleCookie -from django.contrib.contenttypes.models import ContentType -from rest_framework.test import APITestCase +from django.contrib.contenttypes.models import ContentType +from django.urls import reverse from rest_framework import status +from rest_framework.test import APITestCase from account.models import User +from establishment.models import Establishment, EstablishmentType from favorites.models import Favorites -from establishment.models import Establishment, EstablishmentType, EstablishmentSubType from news.models import NewsType, News +from datetime import datetime class BaseTestCase(APITestCase): @@ -17,38 +19,57 @@ class BaseTestCase(APITestCase): self.username = 'sedragurda' self.password = 'sedragurdaredips19' self.email = 'sedragurda@desoz.com' - self.user = User.objects.create_user(username=self.username, email=self.email, password=self.password) - tokkens = User.create_jwt_tokens(self.user) - self.client.cookies = SimpleCookie({'access_token': tokkens.get('access_token'), - 'refresh_token': tokkens.get('refresh_token')}) + self.user = User.objects.create_user( + username=self.username, + email=self.email, + password=self.password + ) - self.test_news_type = NewsType.objects.create(name="Test news type") - self.test_news = News.objects.create(created_by=self.user, modified_by=self.user, title={"en-GB": "Test news"}, - news_type=self.test_news_type, - description={"en-GB": "Description test news"}, - start="2020-12-03 12:00:00", end="2020-12-13 12:00:00", - state=News.PUBLISHED, slug='test-news') + tokens = User.create_jwt_tokens(self.user) + self.client.cookies = SimpleCookie( + {'access_token': tokens.get('access_token'), + 'refresh_token': tokens.get('refresh_token')}) - self.test_content_type = ContentType.objects.get(app_label="news", model="news") + self.test_news_type = NewsType.objects.create( + name="Test news type", + ) + self.test_news = News.objects.create( + created_by=self.user, + modified_by=self.user, + title={"en-GB": "Test news"}, + news_type=self.test_news_type, + description={"en-GB": "Description test news"}, + start=datetime.fromisoformat("2020-12-03 12:00:00"), + end=datetime.fromisoformat("2020-12-03 12:00:00"), + state=News.PUBLISHED, + slug='test-news' + ) - self.test_favorites = Favorites.objects.create(user=self.user, content_type=self.test_content_type, - object_id=self.test_news.id) + self.test_content_type = ContentType.objects.get( + app_label="news", model="news") - self.test_establishment_type = EstablishmentType.objects.create(name={"en-GB": "test establishment type"}, - use_subtypes=False) + self.test_favorites = Favorites.objects.create( + user=self.user, content_type=self.test_content_type, + object_id=self.test_news.id) - self.test_establishment = Establishment.objects.create(name="test establishment", - description={"en-GB": "description of test establishment"}, - establishment_type=self.test_establishment_type, - is_publish=True) + self.test_establishment_type = EstablishmentType.objects.create( + name={"en-GB": "test establishment type"}, + use_subtypes=False) + + self.test_establishment = Establishment.objects.create( + name="test establishment", + description={"en-GB": "description of test establishment"}, + establishment_type=self.test_establishment_type, + is_publish=True) # value for GenericRelation(reverse side) field must be iterable - # value for GenericRelation(reverse side) field must be assigned through "set" method of field + # value for GenericRelation(reverse side) field must be assigned through + # "set" method of field self.test_establishment.favorites.set([self.test_favorites]) class FavoritesTestCase(BaseTestCase): def test_func(self): - response = self.client.get("/api/web/favorites/establishments/") - print(response.json()) + url = reverse('web:favorites:establishment-list') + response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK) \ No newline at end of file diff --git a/apps/news/tests.py b/apps/news/tests.py index f5340d15..115763e5 100644 --- a/apps/news/tests.py +++ b/apps/news/tests.py @@ -18,11 +18,14 @@ class BaseTestCase(APITestCase): self.username = 'sedragurda' self.password = 'sedragurdaredips19' self.email = 'sedragurda@desoz.com' - self.user = User.objects.create_user(username=self.username, email=self.email, password=self.password) - #get tokkens - tokkens = User.create_jwt_tokens(self.user) - self.client.cookies = SimpleCookie({'access_token': tokkens.get('access_token'), - 'refresh_token': tokkens.get('refresh_token')}) + self.user = User.objects.create_user( + username=self.username, email=self.email, password=self.password) + + # get tokens + tokens = User.create_jwt_tokens(self.user) + self.client.cookies = SimpleCookie( + {'access_token': tokens.get('access_token'), + 'refresh_token': tokens.get('refresh_token')}) self.test_news_type = NewsType.objects.create(name="Test news type") self.lang = Language.objects.get( @@ -46,21 +49,25 @@ class BaseTestCase(APITestCase): ) user_role.save() - self.test_news = News.objects.create(created_by=self.user, modified_by=self.user, - title={"en-GB": "Test news"}, - news_type=self.test_news_type, - description={"en-GB": "Description test news"}, - start=datetime.now() + timedelta(hours=-2), - end=datetime.now() + timedelta(hours=2), - state=News.PUBLISHED, slug='test-news-slug', - country=self.country_ru) + self.test_news = News.objects.create( + created_by=self.user, modified_by=self.user, + title={"en-GB": "Test news"}, + news_type=self.test_news_type, + description={"en-GB": "Description test news"}, + start=datetime.now() + timedelta(hours=-2), + end=datetime.now() + timedelta(hours=2), + state=News.PUBLISHED, + slug='test-news-slug', + country=self.country_ru, + ) + class NewsTestCase(BaseTestCase): def setUp(self): super().setUp() def test_web_news(self): - response = self.client.get("/api/web/news/") + response = self.client.get(reverse('web:news:list')) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.client.get(f"/api/web/news/slug/{self.test_news.slug}/") diff --git a/apps/news/urls/back.py b/apps/news/urls/back.py index 4ab11727..9cc3d94a 100644 --- a/apps/news/urls/back.py +++ b/apps/news/urls/back.py @@ -8,7 +8,7 @@ app_name = 'news' urlpatterns = [ path('', views.NewsBackOfficeLCView.as_view(), name='list-create'), path('/', views.NewsBackOfficeRUDView.as_view(), - name='gallery-retrieve-update-destroy'), + name='retrieve-update-destroy'), path('/gallery/', views.NewsBackOfficeGalleryListView.as_view(), name='gallery-list'), path('/gallery//', views.NewsBackOfficeGalleryCreateDestroyView.as_view(), diff --git a/apps/news/views.py b/apps/news/views.py index 51d49be3..9cd5d969 100644 --- a/apps/news/views.py +++ b/apps/news/views.py @@ -20,19 +20,28 @@ class NewsMixinView: def get_queryset(self, *args, **kwargs): from django.conf import settings """Override get_queryset method.""" + qs = models.News.objects.published().with_base_related() \ .order_by('-is_highlighted', '-created') country_code = self.request.country_code - if country_code and country_code != 'www' and country_code != 'main': - return qs.by_country_code(self.request.country_code) - else: - if settings.HARDCODED_INTERNATIONAL_NEWS_IDS: - # Temporary stub for international news logic - # (по договорённости с заказчиком на демонстрации 4 ноября здесь будет 6 фиксированных новостей) - # TODO replace this stub with actual logic - return models.News.objects.filter(id__in=settings.HARDCODED_INTERNATIONAL_NEWS_IDS) - else: + if country_code: + + # temp code + # Temporary stub for international news logic + # (по договорённости с заказчиком на демонстрации 4 ноября + # здесь будет 6 фиксированных новостей) + # TODO replace this stub with actual logic + if hasattr(settings, 'HARDCODED_INTERNATIONAL_NEWS_IDS'): + if country_code and country_code != 'www' and country_code != 'main': + qs = qs.by_country_code(country_code) + else: + qs = models.News.objects.filter( + id__in=settings.HARDCODED_INTERNATIONAL_NEWS_IDS) return qs + # temp code + + qs = qs.by_country_code(country_code) + return qs class NewsListView(NewsMixinView, generics.ListAPIView): diff --git a/apps/utils/tests/tests_translated.py b/apps/utils/tests/tests_translated.py index 7a304095..77b67d8a 100644 --- a/apps/utils/tests/tests_translated.py +++ b/apps/utils/tests/tests_translated.py @@ -27,7 +27,7 @@ class BaseTestCase(APITestCase): self.client.cookies = SimpleCookie( {'access_token': tokkens.get('access_token'), 'refresh_token': tokkens.get('refresh_token'), - 'locale': "en" + 'locale': "en-GB" }) @@ -58,12 +58,11 @@ class TranslateFieldTests(BaseTestCase): def test_model_field(self): self.assertTrue(hasattr(self.news_item, "title_translated")) - def test_read_locale(self): response = self.client.get(f"/api/web/news/slug/{self.news_item.slug}/", format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) news_data = response.json() - + print(news_data) self.assertIn("title_translated", news_data) self.assertIn("Test news item", news_data['title_translated']) diff --git a/docker-compose.yml b/docker-compose.yml index 3b446101..c518a3ad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -31,14 +31,6 @@ services: # Redis redis: image: redis:2.8.23 - ports: - - "6379:6379" - - # RabbitMQ - #rabbitmq: - # image: rabbitmq:latest - # ports: - # - "5672:5672" # Celery worker: diff --git a/project/settings/local.py b/project/settings/local.py index 1b511692..e87b99f6 100644 --- a/project/settings/local.py +++ b/project/settings/local.py @@ -88,8 +88,3 @@ ELASTICSEARCH_INDEX_NAMES = { TESTING = sys.argv[1:2] == ['test'] if TESTING: ELASTICSEARCH_INDEX_NAMES = {} - - -# TMP ( TODO remove it later) -# Временный хардкод для демонстрации 4 ноября, потом удалить! -HARDCODED_INTERNATIONAL_NEWS_IDS = [8, 9, 10, 11, 15, 17] \ No newline at end of file