Merge branch 'develop' into feature/permission_liquor
This commit is contained in:
commit
b48cd4a81c
|
|
@ -1,3 +1,4 @@
|
|||
FROM mdillon/postgis:10
|
||||
RUN localedef -i ru_RU -c -f UTF-8 -A /usr/share/locale/locale.alias ru_RU.UTF-8
|
||||
ENV LANG ru_RU.utf8
|
||||
COPY hstore.sql /docker-entrypoint-initdb.d
|
||||
1
_dockerfiles/db/hstore.sql
Normal file
1
_dockerfiles/db/hstore.sql
Normal file
|
|
@ -0,0 +1 @@
|
|||
create extension hstore;
|
||||
|
|
@ -42,8 +42,9 @@ class BaseTestCase(APITestCase):
|
|||
start=datetime.fromisoformat("2020-12-03 12:00:00"),
|
||||
end=datetime.fromisoformat("2020-12-03 12:00:00"),
|
||||
state=News.PUBLISHED,
|
||||
slug='test-news'
|
||||
slugs={'en-GB': 'test-news'}
|
||||
)
|
||||
self.slug = next(iter(self.test_news.slugs.values()))
|
||||
|
||||
self.test_content_type = ContentType.objects.get(
|
||||
app_label="news", model="news")
|
||||
|
|
|
|||
29
apps/news/migrations/0039_news_slugs.py
Normal file
29
apps/news/migrations/0039_news_slugs.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-10 13:49
|
||||
|
||||
import django.contrib.postgres.fields.hstore
|
||||
from django.db import migrations
|
||||
from django.contrib.postgres.operations import HStoreExtension
|
||||
|
||||
def migrate_slugs(apps, schemaeditor):
|
||||
News = apps.get_model('news', 'News')
|
||||
for news in News.objects.all():
|
||||
if news.slug:
|
||||
news.slugs = {'en-GB': news.slug}
|
||||
news.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('news', '0038_news_backoffice_title'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
HStoreExtension(),
|
||||
migrations.AddField(
|
||||
model_name='news',
|
||||
name='slugs',
|
||||
field=django.contrib.postgres.fields.hstore.HStoreField(blank=True, default=None, help_text='{"en-GB":"some slug"}', null=True, verbose_name='Slugs for current news obj'),
|
||||
),
|
||||
migrations.RunPython(migrate_slugs, migrations.RunPython.noop)
|
||||
]
|
||||
17
apps/news/migrations/0040_remove_news_slug.py
Normal file
17
apps/news/migrations/0040_remove_news_slug.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-10 16:22
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('news', '0039_news_slugs'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='news',
|
||||
name='slug',
|
||||
),
|
||||
]
|
||||
|
|
@ -12,6 +12,7 @@ from utils.models import (BaseAttributes, TJSONField, TranslatedFieldsMixin, Has
|
|||
FavoritesMixin)
|
||||
from utils.querysets import TranslationQuerysetMixin
|
||||
from django.conf import settings
|
||||
from django.contrib.postgres.fields import HStoreField
|
||||
|
||||
|
||||
class Agenda(ProjectBaseMixin, TranslatedFieldsMixin):
|
||||
|
|
@ -180,8 +181,9 @@ class News(GalleryModelMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixi
|
|||
verbose_name=_('Start'))
|
||||
end = models.DateTimeField(blank=True, null=True, default=None,
|
||||
verbose_name=_('End'))
|
||||
slug = models.SlugField(unique=True, max_length=255,
|
||||
verbose_name=_('News slug'))
|
||||
slugs = HStoreField(null=True, blank=True, default=None,
|
||||
verbose_name=_('Slugs for current news obj'),
|
||||
help_text='{"en-GB":"some slug"}')
|
||||
state = models.PositiveSmallIntegerField(default=WAITING, choices=STATE_CHOICES,
|
||||
verbose_name=_('State'))
|
||||
is_highlighted = models.BooleanField(default=False,
|
||||
|
|
@ -230,7 +232,7 @@ class News(GalleryModelMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixi
|
|||
|
||||
@property
|
||||
def web_url(self):
|
||||
return reverse('web:news:rud', kwargs={'slug': self.slug})
|
||||
return reverse('web:news:rud', kwargs={'slug': next(iter(self.slugs.values()))})
|
||||
|
||||
def should_read(self, user):
|
||||
return self.__class__.objects.should_read(self, user)[:3]
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ class NewsBaseSerializer(ProjectModelSerializer):
|
|||
'is_highlighted',
|
||||
'news_type',
|
||||
'tags',
|
||||
'slug',
|
||||
'slugs',
|
||||
'view_counter',
|
||||
)
|
||||
|
||||
|
|
@ -177,6 +177,14 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer):
|
|||
'backoffice_title': {'allow_null': False},
|
||||
}
|
||||
|
||||
def validate(self, attrs):
|
||||
slugs = attrs.get('slugs', {})
|
||||
if models.News.objects.filter(
|
||||
slugs__values__contains=list(slugs.values())
|
||||
).exclude(id=attrs.get('id', 0)).exists():
|
||||
raise serializers.ValidationError({'slugs': _('News with this slug already exists.')})
|
||||
return attrs
|
||||
|
||||
|
||||
class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer,
|
||||
NewsDetailSerializer):
|
||||
|
|
@ -256,7 +264,7 @@ class NewsFavoritesCreateSerializer(FavoritesCreateSerializer):
|
|||
def validate(self, attrs):
|
||||
"""Overridden validate method"""
|
||||
# Check establishment object
|
||||
news_qs = models.News.objects.filter(slug=self.slug)
|
||||
news_qs = models.News.objects.filter(slugs__values__contains=[self.slug])
|
||||
|
||||
# Check establishment obj by slug from lookup_kwarg
|
||||
if not news_qs.exists():
|
||||
|
|
|
|||
|
|
@ -66,10 +66,11 @@ class BaseTestCase(APITestCase):
|
|||
start=datetime.now() + timedelta(hours=-2),
|
||||
end=datetime.now() + timedelta(hours=2),
|
||||
state=News.PUBLISHED,
|
||||
slug='test-news-slug',
|
||||
slugs={'en-GB': 'test-news-slug'},
|
||||
country=self.country_ru,
|
||||
site=self.site_ru
|
||||
)
|
||||
self.slug = next(iter(self.test_news.slugs.values()))
|
||||
|
||||
|
||||
class NewsTestCase(BaseTestCase):
|
||||
|
|
@ -84,7 +85,7 @@ class NewsTestCase(BaseTestCase):
|
|||
"start": datetime.now() + timedelta(hours=-2),
|
||||
"end": datetime.now() + timedelta(hours=2),
|
||||
"state": News.PUBLISHED,
|
||||
"slug": 'test-news-slug_post',
|
||||
"slugs": {'en-GB': 'test-news-slug_post'},
|
||||
"country_id": self.country_ru.id,
|
||||
"site_id": self.site_ru.id
|
||||
}
|
||||
|
|
@ -97,7 +98,7 @@ class NewsTestCase(BaseTestCase):
|
|||
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}/")
|
||||
response = self.client.get(f"/api/web/news/slug/{self.slug}/")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
response = self.client.get("/api/web/news/types/")
|
||||
|
|
@ -117,7 +118,7 @@ class NewsTestCase(BaseTestCase):
|
|||
data = {
|
||||
'id': self.test_news.id,
|
||||
'description': {"ru-RU": "Description test news!"},
|
||||
'slug': self.test_news.slug,
|
||||
'slugs': self.test_news.slugs,
|
||||
'start': self.test_news.start,
|
||||
'news_type_id': self.test_news.news_type_id,
|
||||
'country_id': self.country_ru.id,
|
||||
|
|
@ -133,10 +134,10 @@ class NewsTestCase(BaseTestCase):
|
|||
"object_id": self.test_news.id
|
||||
}
|
||||
|
||||
response = self.client.post(f'/api/web/news/slug/{self.test_news.slug}/favorites/', data=data)
|
||||
response = self.client.post(f'/api/web/news/slug/{self.slug}/favorites/', data=data)
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
|
||||
response = self.client.delete(f'/api/web/news/slug/{self.test_news.slug}/favorites/', format='json')
|
||||
response = self.client.delete(f'/api/web/news/slug/{self.slug}/favorites/', format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ class NewsMixinView:
|
|||
qs = qs.by_country_code(country_code)
|
||||
return qs
|
||||
|
||||
def get_object(self):
|
||||
return self.get_queryset() \
|
||||
.filter(slugs__values__contains=[self.kwargs['slug']]).first()
|
||||
|
||||
|
||||
class NewsListView(NewsMixinView, generics.ListAPIView):
|
||||
"""News list view."""
|
||||
|
|
@ -46,7 +50,7 @@ class NewsListView(NewsMixinView, generics.ListAPIView):
|
|||
class NewsDetailView(NewsMixinView, generics.RetrieveAPIView):
|
||||
"""News detail view."""
|
||||
|
||||
lookup_field = 'slug'
|
||||
lookup_field = None
|
||||
serializer_class = serializers.NewsDetailWebSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from establishment import models
|
|||
|
||||
EstablishmentIndex = Index(settings.ELASTICSEARCH_INDEX_NAMES.get(__name__,
|
||||
'establishment'))
|
||||
EstablishmentIndex.settings(number_of_shards=1, number_of_replicas=1)
|
||||
EstablishmentIndex.settings(number_of_shards=5, number_of_replicas=2)
|
||||
|
||||
|
||||
@EstablishmentIndex.doc_type
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ class NewsDocument(Document):
|
|||
'name': fields.KeywordField()})
|
||||
title = fields.ObjectField(attr='title_indexing',
|
||||
properties=OBJECT_FIELD_PROPERTIES)
|
||||
slugs = fields.ObjectField(properties=OBJECT_FIELD_PROPERTIES)
|
||||
backoffice_title = fields.TextField(analyzer='english')
|
||||
subtitle = fields.ObjectField(attr='subtitle_indexing',
|
||||
properties=OBJECT_FIELD_PROPERTIES)
|
||||
|
|
@ -44,13 +45,16 @@ class NewsDocument(Document):
|
|||
multi=True)
|
||||
favorites_for_users = fields.ListField(field=fields.IntegerField())
|
||||
start = fields.DateField(attr='start')
|
||||
|
||||
def prepare_slugs(self, instance):
|
||||
return {locale: instance.slugs.get(locale) for locale in OBJECT_FIELD_PROPERTIES}
|
||||
|
||||
class Django:
|
||||
|
||||
model = models.News
|
||||
fields = (
|
||||
'id',
|
||||
'end',
|
||||
'slug',
|
||||
'state',
|
||||
'is_highlighted',
|
||||
'template',
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ class NewsDocumentSerializer(InFavoritesMixin, DocumentSerializer):
|
|||
'news_type',
|
||||
'tags',
|
||||
'start',
|
||||
'slug',
|
||||
'slugs',
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
|
|
@ -56,17 +56,18 @@ class TranslateFieldTests(BaseTestCase):
|
|||
start=datetime.now(pytz.utc) + timedelta(hours=-13),
|
||||
end=datetime.now(pytz.utc) + timedelta(hours=13),
|
||||
news_type=self.news_type,
|
||||
slug='test',
|
||||
slugs={'en-GB': 'test'},
|
||||
state=News.PUBLISHED,
|
||||
country=self.country_ru,
|
||||
)
|
||||
self.slug = next(iter(self.news_item.slugs.values()))
|
||||
self.news_item.save()
|
||||
|
||||
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')
|
||||
response = self.client.get(f"/api/web/news/slug/{self.slug}/", format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
news_data = response.json()
|
||||
self.assertIn("title_translated", news_data)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from rest_framework.response import Response
|
|||
|
||||
from gallery.tasks import delete_image
|
||||
from search_indexes.documents import es_update
|
||||
from news.models import News
|
||||
|
||||
|
||||
# JWT
|
||||
|
|
@ -124,6 +125,8 @@ class BaseCreateDestroyMixinView(generics.CreateAPIView, generics.DestroyAPIView
|
|||
lookup_field = 'slug'
|
||||
|
||||
def get_base_object(self):
|
||||
if 'slugs' in [f.name for f in self._model._meta.get_fields()]: # slugs instead of `slug`
|
||||
return get_object_or_404(self._model, slugs__values__contains=[self.kwargs['slug']])
|
||||
return get_object_or_404(self._model, slug=self.kwargs['slug'])
|
||||
|
||||
def es_update_base_object(self):
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ CONTRIB_APPS = [
|
|||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.gis',
|
||||
'django.contrib.postgres',
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user