This commit is contained in:
Виктор Гладких 2019-11-25 16:52:27 +03:00
commit 420c673afd
40 changed files with 701 additions and 151 deletions

View File

@ -55,3 +55,23 @@ class EstablishmentTypeTagFilter(filters.FilterSet):
fields = (
'type_id',
)
class EmployeeBackFilter(filters.FilterSet):
"""Employee filter set."""
search = filters.CharFilter(method='search_by_name_or_last_name')
class Meta:
"""Meta class."""
model = models.Employee
fields = (
'search',
)
def search_by_name_or_last_name(self, queryset, name, value):
"""Search by name or last name."""
if value not in EMPTY_VALUES:
return queryset.search_by_name_or_last_name(value)
return queryset

View File

@ -0,0 +1,28 @@
# Generated by Django 2.2.7 on 2019-11-22 11:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('establishment', '0065_establishment_purchased_products'),
]
operations = [
migrations.AddField(
model_name='employee',
name='last_name',
field=models.CharField(default=None, max_length=255, null=True, verbose_name='Last Name'),
),
migrations.AddField(
model_name='establishmentemployee',
name='status',
field=models.CharField(choices=[('I', 'Idle'), ('A', 'Accepted'), ('D', 'Declined')], default='I', max_length=1),
),
migrations.AlterField(
model_name='employee',
name='name',
field=models.CharField(max_length=255, verbose_name='Name'),
),
]

View File

@ -0,0 +1,39 @@
# Generated by Django 2.2.7 on 2019-11-22 12:44
from django.db import migrations, models
import phonenumber_field.modelfields
class Migration(migrations.Migration):
dependencies = [
('establishment', '0066_auto_20191122_1144'),
]
operations = [
migrations.AddField(
model_name='employee',
name='birth_date',
field=models.DateTimeField(default=None, null=True, verbose_name='Birth date'),
),
migrations.AddField(
model_name='employee',
name='email',
field=models.EmailField(blank=True, default=None, max_length=254, null=True, verbose_name='Email'),
),
migrations.AddField(
model_name='employee',
name='phone',
field=phonenumber_field.modelfields.PhoneNumberField(default=None, max_length=128, null=True),
),
migrations.AddField(
model_name='employee',
name='sex',
field=models.PositiveSmallIntegerField(choices=[(0, 'Male'), (1, 'Female')], default=None, null=True, verbose_name='Sex'),
),
migrations.AddField(
model_name='employee',
name='toque_number',
field=models.PositiveSmallIntegerField(default=None, null=True, verbose_name='Toque number'),
),
]

View File

@ -1,6 +1,7 @@
"""Establishment models."""
from datetime import datetime
from functools import reduce
from typing import List
from operator import or_
import elasticsearch_dsl
@ -118,11 +119,13 @@ class EstablishmentQuerySet(models.QuerySet):
'address__city__country')
def with_extended_related(self):
return self.select_related('establishment_type'). \
return self.with_extended_address_related().select_related('establishment_type'). \
prefetch_related('establishment_subtypes', 'awards', 'schedule',
'phones'). \
'phones', 'gallery', 'menu_set', 'menu_set__plate_set',
'menu_set__plate_set__currency', 'currency'). \
prefetch_actual_employees()
def with_type_related(self):
return self.prefetch_related('establishment_subtypes')
@ -395,6 +398,7 @@ class Establishment(GalleryModelMixin, ProjectBaseMixin, URLImageMixin,
verbose_name=_('Tag'))
reviews = generic.GenericRelation(to='review.Review')
comments = generic.GenericRelation(to='comment.Comment')
carousels = generic.GenericRelation(to='main.Carousel')
favorites = generic.GenericRelation(to='favorites.Favorites')
currency = models.ForeignKey(Currency, blank=True, null=True, default=None,
on_delete=models.PROTECT,
@ -434,11 +438,12 @@ class Establishment(GalleryModelMixin, ProjectBaseMixin, URLImageMixin,
@property
def visible_tags(self):
return super().visible_tags\
.exclude(category__index_name__in=['guide', 'collection', 'purchased_item',
'business_tag', 'business_tags_de'])\
return super().visible_tags \
.exclude(category__index_name__in=['guide', 'collection', 'purchased_item',
'business_tag', 'business_tags_de']) \
\
# todo: recalculate toque_number
# todo: recalculate toque_number
def recalculate_toque_number(self):
toque_number = 0
if self.address and self.public_mark:
@ -611,7 +616,6 @@ class EstablishmentNote(ProjectBaseMixin):
class EstablishmentGallery(IntermediateGalleryModelMixin):
establishment = models.ForeignKey(Establishment, null=True,
related_name='establishment_gallery',
on_delete=models.CASCADE,
@ -662,6 +666,16 @@ class EstablishmentEmployeeQuerySet(models.QuerySet):
class EstablishmentEmployee(BaseAttributes):
"""EstablishmentEmployee model."""
IDLE = 'I'
ACCEPTED = 'A'
DECLINED = 'D'
STATUS_CHOICES = (
(IDLE, 'Idle'),
(ACCEPTED, 'Accepted'),
(DECLINED, 'Declined'),
)
establishment = models.ForeignKey(Establishment, on_delete=models.PROTECT,
verbose_name=_('Establishment'))
employee = models.ForeignKey('establishment.Employee', on_delete=models.PROTECT,
@ -672,19 +686,53 @@ class EstablishmentEmployee(BaseAttributes):
verbose_name=_('To date'))
position = models.ForeignKey(Position, on_delete=models.PROTECT,
verbose_name=_('Position'))
status = models.CharField(max_length=1, choices=STATUS_CHOICES, default=IDLE)
# old_id = affiliations_id
old_id = models.IntegerField(verbose_name=_('Old id'), null=True, blank=True)
objects = EstablishmentEmployeeQuerySet.as_manager()
class EmployeeQuerySet(models.QuerySet):
def _generic_search(self, value, filter_fields_names: List[str]):
"""Generic method for searching value in specified fields"""
filters = [
{f'{field}__icontains': value}
for field in filter_fields_names
]
return self.filter(reduce(lambda x, y: x | y, [models.Q(**i) for i in filters]))
def search_by_name_or_last_name(self, value):
"""Search by name or last_name."""
return self._generic_search(value, ['name', 'last_name'])
class Employee(BaseAttributes):
"""Employee model."""
user = models.OneToOneField('account.User', on_delete=models.PROTECT,
null=True, blank=True, default=None,
verbose_name=_('User'))
name = models.CharField(max_length=255, verbose_name=_('Last name'))
name = models.CharField(max_length=255, verbose_name=_('Name'))
last_name = models.CharField(max_length=255, verbose_name=_('Last Name'), null=True, default=None)
# SEX CHOICES
MALE = 0
FEMALE = 1
SEX_CHOICES = (
(MALE, _('Male')),
(FEMALE, _('Female'))
)
sex = models.PositiveSmallIntegerField(choices=SEX_CHOICES, verbose_name=_('Sex'), null=True, default=None)
birth_date = models.DateTimeField(editable=True, verbose_name=_('Birth date'), null=True, default=None)
email = models.EmailField(blank=True, null=True, default=None, verbose_name=_('Email'))
phone = PhoneNumberField(null=True, default=None)
toque_number = models.PositiveSmallIntegerField(verbose_name=_('Toque number'), null=True, default=None)
establishments = models.ManyToManyField(Establishment, related_name='employees',
through=EstablishmentEmployee, )
awards = generic.GenericRelation(to='main.Award', related_query_name='employees')
@ -693,6 +741,8 @@ class Employee(BaseAttributes):
# old_id = profile_id
old_id = models.IntegerField(verbose_name=_('Old id'), null=True, blank=True)
objects = EmployeeQuerySet.as_manager()
class Meta:
"""Meta class."""

View File

@ -2,8 +2,9 @@ from rest_framework import serializers
from establishment import models
from establishment import serializers as model_serializers
from location.serializers import AddressDetailSerializer
from location.serializers import AddressDetailSerializer, TranslatedField
from main.models import Currency
from main.serializers import AwardSerializer
from utils.decorators import with_base_attributes
from utils.serializers import TimeZoneChoiceField
from gallery.models import Image
@ -161,12 +162,54 @@ class ContactEmailBackSerializers(model_serializers.PlateSerializer):
class EmployeeBackSerializers(serializers.ModelSerializer):
"""Employee serializers."""
awards = AwardSerializer(many=True, read_only=True)
class Meta:
model = models.Employee
fields = [
'id',
'user',
'name'
'name',
'last_name',
'sex',
'birth_date',
'email',
'phone',
'toque_number',
'awards',
]
class PositionBackSerializer(serializers.ModelSerializer):
"""Position Back serializer."""
name_translated = TranslatedField()
class Meta:
model = models.Position
fields = [
'id',
'name_translated',
'priority',
'index_name',
]
class EstablishmentEmployeeBackSerializer(serializers.ModelSerializer):
"""Establishment Employee serializer."""
employee = EmployeeBackSerializers()
position = PositionBackSerializer()
class Meta:
model = models.EstablishmentEmployee
fields = [
'id',
'employee',
'from_date',
'to_date',
'position',
'status',
]

View File

@ -13,7 +13,7 @@ from review.serializers import ReviewShortSerializer
from tag.serializers import TagBaseSerializer
from timetable.serialziers import ScheduleRUDSerializer
from utils import exceptions as utils_exceptions
from utils.serializers import ImageBaseSerializer
from utils.serializers import ImageBaseSerializer, CarouselCreateSerializer
from utils.serializers import (ProjectModelSerializer, TranslatedField,
FavoritesCreateSerializer)
@ -168,12 +168,51 @@ class EstablishmentEmployeeSerializer(serializers.ModelSerializer):
awards = AwardSerializer(source='employee.awards', many=True)
priority = serializers.IntegerField(source='position.priority')
position_index_name = serializers.CharField(source='position.index_name')
status = serializers.CharField()
class Meta:
"""Meta class."""
model = models.Employee
fields = ('id', 'name', 'position_translated', 'awards', 'priority', 'position_index_name')
fields = ('id', 'name', 'position_translated', 'awards', 'priority', 'position_index_name', 'status')
class EstablishmentEmployeeCreateSerializer(serializers.ModelSerializer):
"""Serializer for establishment employee relation."""
class Meta:
"""Meta class."""
model = models.EstablishmentEmployee
fields = ('id',)
def _validate_entity(self, entity_id_param: str, entity_class):
entity_id = self.context.get('request').parser_context.get('kwargs').get(entity_id_param)
entity_qs = entity_class.objects.filter(id=entity_id)
if not entity_qs.exists():
raise serializers.ValidationError({'detail': _(f'{entity_class.__name__} not found.')})
return entity_qs.first()
def validate(self, attrs):
"""Override validate method"""
establishment = self._validate_entity("establishment_id", models.Establishment)
employee = self._validate_entity("employee_id", models.Employee)
position = self._validate_entity("position_id", models.Position)
attrs['establishment'] = establishment
attrs['employee'] = employee
attrs['position'] = position
return attrs
def create(self, validated_data, *args, **kwargs):
"""Override create method"""
validated_data.update({
'employee': validated_data.pop('employee'),
'establishment': validated_data.pop('establishment'),
'position': validated_data.pop("position")
})
return super().create(validated_data)
class EstablishmentShortSerializer(serializers.ModelSerializer):
@ -396,6 +435,22 @@ class EstablishmentCommentCreateSerializer(comment_serializers.CommentSerializer
return super().create(validated_data)
class EstablishmentCommentRUDSerializer(comment_serializers.CommentSerializer):
"""Retrieve/Update/Destroy comment serializer."""
class Meta:
"""Meta class."""
model = comment_models.Comment
fields = [
'id',
'created',
'text',
'mark',
'nickname',
'profile_pic',
]
class EstablishmentFavoritesCreateSerializer(FavoritesCreateSerializer):
"""Serializer to favorite object w/ model Establishment."""
@ -426,6 +481,27 @@ class EstablishmentFavoritesCreateSerializer(FavoritesCreateSerializer):
return super().create(validated_data)
class EstablishmentCarouselCreateSerializer(CarouselCreateSerializer):
"""Serializer to carousel object w/ model News."""
def validate(self, attrs):
establishment = models.Establishment.objects.filter(pk=self.pk).first()
if not establishment:
raise serializers.ValidationError({'detail': _('Object not found.')})
if establishment.carousels.exists():
raise utils_exceptions.CarouselError()
attrs['establishment'] = establishment
return attrs
def create(self, validated_data, *args, **kwargs):
validated_data.update({
'content_object': validated_data.pop('establishment')
})
return super().create(validated_data)
class CompanyBaseSerializer(serializers.ModelSerializer):
"""Company base serializer"""
phone_list = serializers.SerializerMethodField(source='phones', read_only=True)

View File

@ -475,3 +475,17 @@ class EstablishmentWebFavoriteTests(ChildTestCase):
f'/api/web/establishments/slug/{self.establishment.slug}/favorites/',
format='json')
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
class EstablishmentCarouselTests(ChildTestCase):
def test_back_carousel_CR(self):
data = {
"object_id": self.establishment.id
}
response = self.client.post(f'/api/back/establishments/{self.establishment.id}/carousels/', data=data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
response = self.client.delete(f'/api/back/establishments/{self.establishment.id}/carousels/')
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

View File

@ -9,6 +9,8 @@ app_name = 'establishment'
urlpatterns = [
path('', views.EstablishmentListCreateView.as_view(), name='list'),
path('<int:pk>/', views.EstablishmentRUDView.as_view(), name='detail'),
path('<int:pk>/carousels/', views.EstablishmentCarouselCreateDestroyView.as_view(),
name='create-destroy-carousels'),
path('<int:pk>/schedule/<int:schedule_id>/', views.EstablishmentScheduleRUDView.as_view(),
name='schedule-rud'),
path('<int:pk>/schedule/', views.EstablishmentScheduleCreateView.as_view(),
@ -38,10 +40,19 @@ urlpatterns = [
path('phones/<int:pk>/', views.PhonesRUDView.as_view(), name='phones-rud'),
path('emails/', views.EmailListCreateView.as_view(), name='emails'),
path('emails/<int:pk>/', views.EmailRUDView.as_view(), name='emails-rud'),
path('<int:establishment_id>/employees/', views.EstablishmentEmployeeListView.as_view(),
name='establishment-employees'),
path('employees/', views.EmployeeListCreateView.as_view(), name='employees'),
path('employees/<int:pk>/', views.EmployeeRUDView.as_view(), name='employees-rud'),
path('<int:establishment_id>/employee/<int:employee_id>/position/<int:position_id>',
views.EstablishmentEmployeeCreateView.as_view(),
name='employees-establishment-create'),
path('<int:establishment_id>/employee/<int:employee_id>',
views.EstablishmentEmployeeDeleteView.as_view(),
name='employees-establishment-delete'),
path('types/', views.EstablishmentTypeListCreateView.as_view(), name='type-list'),
path('types/<int:pk>/', views.EstablishmentTypeRUDView.as_view(), name='type-rud'),
path('subtypes/', views.EstablishmentSubtypeListCreateView.as_view(), name='subtype-list'),
path('subtypes/<int:pk>/', views.EstablishmentSubtypeRUDView.as_view(), name='subtype-rud'),
path('positions/', views.EstablishmentPositionListView.as_view(), name='position-list'),
]

View File

@ -17,5 +17,5 @@ urlpatterns = [
path('slug/<slug:slug>/comments/<int:comment_id>/', views.EstablishmentCommentRUDView.as_view(),
name='rud-comment'),
path('slug/<slug:slug>/favorites/', views.EstablishmentFavoritesCreateDestroyView.as_view(),
name='create-destroy-favorites')
name='create-destroy-favorites'),
]

View File

@ -1,7 +1,9 @@
"""Establishment app views."""
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from rest_framework import generics, permissions
from rest_framework import generics, permissions, status
from utils.permissions import IsCountryAdmin, IsEstablishmentManager
from establishment import filters, models, serializers
from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer
from utils.permissions import IsCountryAdmin, IsEstablishmentManager
@ -43,8 +45,8 @@ class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView):
"""
Returns the object the view is displaying.
"""
establishment_pk = self.kwargs.get('pk')
schedule_id = self.kwargs.get('schedule_id')
establishment_pk = self.kwargs['pk']
schedule_id = self.kwargs['schedule_id']
establishment = get_object_or_404(klass=models.Establishment.objects.all(),
pk=establishment_pk)
@ -156,11 +158,23 @@ class EmailRUDView(generics.RetrieveUpdateDestroyAPIView):
class EmployeeListCreateView(generics.ListCreateAPIView):
"""Emplyoee list create view."""
permission_classes = (permissions.AllowAny, )
filter_class = filters.EmployeeBackFilter
serializer_class = serializers.EmployeeBackSerializers
queryset = models.Employee.objects.all()
pagination_class = None
class EstablishmentEmployeeListView(generics.ListAPIView):
"""Establishment emplyoees list view."""
permission_classes = (permissions.AllowAny, )
serializer_class = serializers.EstablishmentEmployeeBackSerializer
def get_queryset(self):
establishment_id = self.kwargs['establishment_id']
return models.EstablishmentEmployee.objects.filter(establishment__id=establishment_id)
class EmployeeRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Employee RUD view."""
serializer_class = serializers.EmployeeBackSerializers
@ -318,3 +332,36 @@ class EstablishmentNoteRUDView(EstablishmentMixinViews,
self.check_object_permissions(self.request, note)
return note
class EstablishmentEmployeeCreateView(generics.CreateAPIView):
serializer_class = serializers.EstablishmentEmployeeCreateSerializer
queryset = models.EstablishmentEmployee.objects.all()
# TODO send email to all admins and add endpoint for changing status
class EstablishmentEmployeeDeleteView(generics.DestroyAPIView):
def _get_object_to_delete(self, establishment_id, employee_id):
result_qs = models.EstablishmentEmployee\
.objects\
.filter(establishment_id=establishment_id, employee_id=employee_id)
if not result_qs.exists():
raise Http404
return result_qs.first()
def delete(self, request, *args, **kwargs):
establishment_id = self.kwargs["establishment_id"]
employee_id = self.kwargs["employee_id"]
object_to_delete = self._get_object_to_delete(establishment_id, employee_id)
object_to_delete.delete()
return HttpResponse(status=status.HTTP_204_NO_CONTENT)
class EstablishmentPositionListView(generics.ListAPIView):
"""Establishment positions list view."""
pagination_class = None
permission_classes = (permissions.AllowAny, )
queryset = models.Position.objects.all()
serializer_class = serializers.PositionBackSerializer

View File

@ -9,7 +9,7 @@ from comment.serializers import CommentRUDSerializer
from establishment import filters, models, serializers
from main import methods
from utils.pagination import EstablishmentPortionPagination
from utils.views import FavoritesCreateDestroyMixinView
from utils.views import FavoritesCreateDestroyMixinView, CarouselCreateDestroyMixinView
class EstablishmentMixinView:
@ -34,7 +34,7 @@ class EstablishmentListView(EstablishmentMixinView, generics.ListAPIView):
serializer_class = serializers.EstablishmentListRetrieveSerializer
def get_queryset(self):
return super().get_queryset().with_schedule()\
return super().get_queryset().with_schedule() \
.with_extended_address_related().with_currency_related()
@ -56,12 +56,11 @@ class EstablishmentRecentReviewListView(EstablishmentListView):
def get_queryset(self):
"""Overridden method 'get_queryset'."""
qs = super().get_queryset()
user_ip = methods.get_user_ip(self.request)
query_params = self.request.query_params
if 'longitude' in query_params and 'latitude' in query_params:
longitude, latitude = query_params.get('longitude'), query_params.get('latitude')
else:
longitude, latitude = methods.determine_coordinates(user_ip)
longitude, latitude = methods.determine_coordinates(self.request)
if not longitude or not latitude:
return qs.none()
point = Point(x=float(longitude), y=float(latitude), srid=settings.GEO_DEFAULT_SRID)
@ -106,9 +105,9 @@ class EstablishmentCommentListView(generics.ListAPIView):
establishment = get_object_or_404(models.Establishment, slug=self.kwargs['slug'])
return comment_models.Comment.objects.by_content_type(app_label='establishment',
model='establishment')\
.by_object_id(object_id=establishment.pk)\
.order_by('-created')
model='establishment') \
.by_object_id(object_id=establishment.pk) \
.order_by('-created')
class EstablishmentCommentRUDView(generics.RetrieveUpdateDestroyAPIView):
@ -140,6 +139,13 @@ class EstablishmentFavoritesCreateDestroyView(FavoritesCreateDestroyMixinView):
serializer_class = serializers.EstablishmentFavoritesCreateSerializer
class EstablishmentCarouselCreateDestroyView(CarouselCreateDestroyMixinView):
"""View for create/destroy establishment from carousel."""
_model = models.Establishment
serializer_class = serializers.EstablishmentCarouselCreateSerializer
class EstablishmentNearestRetrieveView(EstablishmentListView, generics.ListAPIView):
"""Resource for getting list of nearest establishments."""

View File

@ -1,4 +1,9 @@
from django.conf import settings
from django.core.validators import MinValueValidator, MaxValueValidator
from rest_framework import serializers
from sorl.thumbnail.parsers import parse_crop
from sorl.thumbnail.parsers import ThumbnailParseError
from django.utils.translation import gettext_lazy as _
from . import models
@ -29,3 +34,86 @@ class ImageSerializer(serializers.ModelSerializer):
extra_kwargs = {
'orientation': {'write_only': True}
}
class CropImageSerializer(ImageSerializer):
"""Serializers for image crops."""
width = serializers.IntegerField(write_only=True, required=False)
height = serializers.IntegerField(write_only=True, required=False)
crop = serializers.CharField(write_only=True,
required=False,
default='center')
quality = serializers.IntegerField(write_only=True, required=False,
default=settings.THUMBNAIL_QUALITY,
validators=[
MinValueValidator(1),
MaxValueValidator(100)])
cropped_image = serializers.DictField(read_only=True, allow_null=True)
class Meta(ImageSerializer.Meta):
"""Meta class."""
fields = [
'id',
'url',
'orientation_display',
'width',
'height',
'crop',
'quality',
'cropped_image',
]
def validate(self, attrs):
"""Overridden validate method."""
file = self._image.image
crop_width = attrs.get('width')
crop_height = attrs.get('height')
crop = attrs.get('crop')
if (crop_height and crop_width) and (crop and crop != 'smart'):
xy_image = (file.width, file.width)
xy_window = (crop_width, crop_height)
try:
parse_crop(crop, xy_image, xy_window)
attrs['image'] = file
except ThumbnailParseError:
raise serializers.ValidationError({'margin': _('Unrecognized crop option: %s') % crop})
return attrs
def create(self, validated_data):
"""Overridden create method."""
width = validated_data.pop('width', None)
height = validated_data.pop('height', None)
quality = validated_data.pop('quality')
crop = validated_data.pop('crop')
image = self._image
if image and width and height:
setattr(image,
'cropped_image',
image.get_cropped_image(
geometry=f'{width}x{height}',
quality=quality,
crop=crop))
return image
@property
def view(self):
return self.context.get('view')
@property
def lookup_field(self):
lookup_field = 'pk'
if lookup_field in self.view.kwargs:
return self.view.kwargs.get(lookup_field)
@property
def _image(self):
"""Return image from url_kwargs."""
qs = models.Image.objects.filter(id=self.lookup_field)
if qs.exists():
return qs.first()
raise serializers.ValidationError({'detail': _('Image not found.')})

View File

@ -6,6 +6,7 @@ from . import views
app_name = 'gallery'
urlpatterns = [
path('', views.ImageListCreateView.as_view(), name='list-create-image'),
path('<int:pk>/', views.ImageRetrieveDestroyView.as_view(), name='retrieve-destroy-image'),
path('', views.ImageListCreateView.as_view(), name='list-create'),
path('<int:pk>/', views.ImageRetrieveDestroyView.as_view(), name='retrieve-destroy'),
path('<int:pk>/crop/', views.CropImageCreateView.as_view(), name='create-crop'),
]

View File

@ -28,3 +28,8 @@ class ImageRetrieveDestroyView(ImageBaseView, generics.RetrieveDestroyAPIView):
else:
on_commit(lambda: tasks.delete_image(image_id=instance.id))
return Response(status=status.HTTP_204_NO_CONTENT)
class CropImageCreateView(ImageBaseView, generics.CreateAPIView):
"""Create crop image."""
serializer_class = serializers.CropImageSerializer

View File

@ -3,9 +3,15 @@ from django.contrib import admin
from main import models
class SiteSettingsInline(admin.TabularInline):
model = models.SiteFeature
extra = 1
@admin.register(models.SiteSettings)
class SiteSettingsAdmin(admin.ModelAdmin):
"""Site settings admin conf."""
inlines = [SiteSettingsInline,]
@admin.register(models.Feature)

View File

@ -28,31 +28,25 @@ def get_user_ip(request):
return ip
def determine_country_code(ip_addr):
def determine_country_code(request):
"""Determine country code."""
country_code = None
if ip_addr:
try:
geoip = GeoIP2()
country_code = geoip.country_code(ip_addr)
country_code = country_code.lower()
except GeoIP2Exception as ex:
logger.info(f'GEOIP Exception: {ex}. ip: {ip_addr}')
except Exception as ex:
logger.error(f'GEOIP Base exception: {ex}')
return country_code
META = request.META
country_code = META.get('X-GeoIP-Country-Code',
META.get('HTTP_X_GEOIP_COUNTRY_CODE'))
if isinstance(country_code, str):
return country_code.lower()
def determine_coordinates(ip_addr: str) -> Tuple[Optional[float], Optional[float]]:
if ip_addr:
try:
geoip = GeoIP2()
return geoip.coords(ip_addr)
except GeoIP2Exception as ex:
logger.warning(f'GEOIP Exception: {ex}. ip: {ip_addr}')
except Exception as ex:
logger.warning(f'GEOIP Base exception: {ex}')
return None, None
def determine_coordinates(request):
META = request.META
longitude = META.get('X-GeoIP-Longitude',
META.get('HTTP_X_GEOIP_LONGITUDE'))
latitude = META.get('X-GeoIP-Latitude',
META.get('HTTP_X_GEOIP_LATITUDE'))
try:
return float(longitude), float(latitude)
except (TypeError, ValueError):
return None, None
def determine_user_site_url(country_code):
@ -76,15 +70,11 @@ def determine_user_site_url(country_code):
return site.site_url
def determine_user_city(ip_addr: str) -> Optional[City]:
try:
geoip = GeoIP2()
return geoip.city(ip_addr)
except GeoIP2Exception as ex:
logger.warning(f'GEOIP Exception: {ex}. ip: {ip_addr}')
except Exception as ex:
logger.warning(f'GEOIP Base exception: {ex}')
return None
def determine_user_city(request):
META = request.META
city = META.get('X-GeoIP-City',
META.get('HTTP_X_GEOIP_CITY'))
return city
def determine_subdivision(

View File

@ -86,9 +86,8 @@ class DetermineLocation(generics.GenericAPIView):
serializer_class = EmptySerializer
def get(self, request, *args, **kwargs):
user_ip = methods.get_user_ip(request)
longitude, latitude = methods.determine_coordinates(user_ip)
city = methods.determine_user_city(user_ip)
longitude, latitude = methods.determine_coordinates(request)
city = methods.determine_user_city(request)
if longitude and latitude and city:
return Response(data={'latitude': latitude, 'longitude': longitude, 'city': city})
else:

View File

@ -14,8 +14,7 @@ class DetermineSiteView(generics.GenericAPIView):
serializer_class = EmptySerializer
def get(self, request, *args, **kwargs):
user_ip = methods.get_user_ip(request)
country_code = methods.determine_country_code(user_ip)
country_code = methods.determine_country_code(request)
url = methods.determine_user_site_url(country_code)
return Response(data={'url': url})

View File

@ -196,6 +196,7 @@ class News(GalleryModelMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixi
views_count = models.OneToOneField('rating.ViewCount', blank=True, null=True, on_delete=models.SET_NULL)
ratings = generic.GenericRelation(Rating)
favorites = generic.GenericRelation(to='favorites.Favorites')
carousels = generic.GenericRelation(to='main.Carousel')
agenda = models.ForeignKey('news.Agenda', blank=True, null=True,
on_delete=models.SET_NULL,
verbose_name=_('agenda'))

View File

@ -12,7 +12,7 @@ from news import models
from tag.serializers import TagBaseSerializer
from utils import exceptions as utils_exceptions
from utils.serializers import (TranslatedField, ProjectModelSerializer,
FavoritesCreateSerializer, ImageBaseSerializer)
FavoritesCreateSerializer, ImageBaseSerializer, CarouselCreateSerializer)
class AgendaSerializer(ProjectModelSerializer):
@ -66,6 +66,7 @@ class NewsBaseSerializer(ProjectModelSerializer):
subtitle_translated = TranslatedField()
news_type = NewsTypeSerializer(read_only=True)
tags = TagBaseSerializer(read_only=True, many=True, source='visible_tags')
in_favorites = serializers.BooleanField(allow_null=True, read_only=True)
view_counter = serializers.IntegerField(read_only=True)
class Meta:
@ -272,3 +273,24 @@ class NewsFavoritesCreateSerializer(FavoritesCreateSerializer):
'content_object': validated_data.pop('news')
})
return super().create(validated_data)
class NewsCarouselCreateSerializer(CarouselCreateSerializer):
"""Serializer to carousel object w/ model News."""
def validate(self, attrs):
news = models.News.objects.filter(pk=self.pk).first()
if not news:
raise serializers.ValidationError({'detail': _('Object not found.')})
if news.carousels.exists():
raise utils_exceptions.CarouselError()
attrs['news'] = news
return attrs
def create(self, validated_data, *args, **kwargs):
validated_data.update({
'content_object': validated_data.pop('news')
})
return super().create(validated_data)

View File

@ -31,6 +31,7 @@ class BaseTestCase(APITestCase):
'refresh_token': tokens.get('refresh_token')})
self.test_news_type = NewsType.objects.create(name="Test news type")
self.lang, created = Language.objects.get_or_create(
title='Russia',
locale='ru-RU'
@ -137,3 +138,17 @@ class NewsTestCase(BaseTestCase):
response = self.client.delete(f'/api/web/news/slug/{self.test_news.slug}/favorites/', format='json')
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
class NewsCarouselTests(BaseTestCase):
def test_back_carousel_CR(self):
data = {
"object_id": self.test_news.id
}
response = self.client.post(f'/api/back/news/{self.test_news.id}/carousels/', data=data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
response = self.client.delete(f'/api/back/news/{self.test_news.id}/carousels/')
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

View File

@ -13,4 +13,5 @@ urlpatterns = [
name='gallery-list'),
path('<int:pk>/gallery/<int:image_id>/', views.NewsBackOfficeGalleryCreateDestroyView.as_view(),
name='gallery-create-destroy'),
]
path('<int:pk>/carousels/', views.NewsCarouselCreateDestroyView.as_view(), name='create-destroy-carousels'),
]

View File

@ -5,5 +5,6 @@ common_urlpatterns = [
path('', views.NewsListView.as_view(), name='list'),
path('types/', views.NewsTypeListView.as_view(), name='type'),
path('slug/<slug:slug>/', views.NewsDetailView.as_view(), name='rud'),
path('slug/<slug:slug>/favorites/', views.NewsFavoritesCreateDestroyView.as_view(), name='create-destroy-favorites')
path('slug/<slug:slug>/favorites/', views.NewsFavoritesCreateDestroyView.as_view(),
name='create-destroy-favorites'),
]

View File

@ -6,7 +6,7 @@ from rest_framework import generics, permissions
from news import filters, models, serializers
from rating.tasks import add_rating
from utils.permissions import IsCountryAdmin, IsContentPageManager
from utils.views import CreateDestroyGalleryViewMixin, FavoritesCreateDestroyMixinView
from utils.views import CreateDestroyGalleryViewMixin, FavoritesCreateDestroyMixinView, CarouselCreateDestroyMixinView
from utils.serializers import ImageBaseSerializer
@ -156,3 +156,10 @@ class NewsFavoritesCreateDestroyView(FavoritesCreateDestroyMixinView):
_model = models.News
serializer_class = serializers.NewsFavoritesCreateSerializer
class NewsCarouselCreateDestroyView(CarouselCreateDestroyMixinView):
"""View for create/destroy news from carousel."""
_model = models.News
serializer_class = serializers.NewsCarouselCreateSerializer

View File

@ -13,7 +13,7 @@ from product.models import Product
logger = logging.getLogger(__name__)
@periodic_task(run_every=crontab(minute=1))
@periodic_task(run_every=crontab(minute='*/1'))
def update_index():
"""Updates ES index."""
try:

View File

@ -31,7 +31,7 @@ class NewsDocumentViewSet(BaseDocumentViewSet):
faceted_search_fields = {
'tag': {
'field': 'tags.value',
'field': 'tags.id',
'enabled': True,
'facet': TermsFacet,
},
@ -122,7 +122,7 @@ class EstablishmentDocumentViewSet(BaseDocumentViewSet):
'enabled': True,
},
'tag': {
'field': 'tags.value',
'field': 'visible_tags.id',
'facet': TermsFacet,
'enabled': True,
},

View File

@ -1,3 +1,5 @@
from django.contrib.auth.models import AbstractUser
def with_base_attributes(cls):
@ -8,7 +10,7 @@ def with_base_attributes(cls):
if request and hasattr(request, "user"):
user = request.user
if user is not None:
if user is not None and isinstance(user, AbstractUser):
data.update({'modified_by': user})
if not self.instance:

View File

@ -135,6 +135,14 @@ class FavoritesError(exceptions.APIException):
default_detail = _('Item is already in favorites.')
class CarouselError(exceptions.APIException):
"""
The exception should be thrown when the object is already in carousels.
"""
status_code = status.HTTP_400_BAD_REQUEST
default_detail = _('Item is already in carousels.')
class PasswordResetRequestExistedError(exceptions.APIException):
"""
The exception should be thrown when password reset request

View File

@ -11,11 +11,11 @@ from django.contrib.postgres.fields.jsonb import KeyTextTransform
from django.utils import timezone
from django.utils.html import mark_safe
from django.utils.translation import ugettext_lazy as _, get_language
from configuration.models import TranslationSettings
from easy_thumbnails.fields import ThumbnailerImageField
from sorl.thumbnail import get_thumbnail
from sorl.thumbnail.fields import ImageField as SORLImageField
from configuration.models import TranslationSettings
from utils.methods import image_path, svg_image_path
from utils.validators import svg_image_validator
@ -223,6 +223,18 @@ class SORLImageMixin(models.Model):
else:
return None
def get_cropped_image(self, geometry: str, quality: int, crop: str) -> dict:
cropped_image = get_thumbnail(self.image,
geometry_string=geometry,
crop=crop,
quality=quality)
return {
'geometry_string': geometry,
'crop_url': cropped_image.url,
'quality': quality,
'crop': crop
}
image_tag.short_description = _('Image')
image_tag.allow_tags = True
@ -439,4 +451,5 @@ class FavoritesMixin:
def favorites_for_users(self):
return self.favorites.aggregate(arr=ArrayAgg('user_id')).get('arr')
timezone.datetime.now().date().isoformat()

View File

@ -2,10 +2,11 @@
import pytz
from django.core import exceptions
from rest_framework import serializers
from utils import models
from translation.models import Language
from favorites.models import Favorites
from gallery.models import Image
from main.models import Carousel
from translation.models import Language
from utils import models
class EmptySerializer(serializers.Serializer):
@ -80,7 +81,6 @@ class FavoritesCreateSerializer(serializers.ModelSerializer):
"""Serializer to favorite object."""
class Meta:
"""Serializer for model Comment."""
model = Favorites
fields = [
'id',
@ -101,6 +101,24 @@ class FavoritesCreateSerializer(serializers.ModelSerializer):
return self.request.parser_context.get('kwargs').get('slug')
class CarouselCreateSerializer(serializers.ModelSerializer):
"""Carousel to favorite object."""
class Meta:
model = Carousel
fields = [
'id',
]
@property
def request(self):
return self.context.get('request')
@property
def pk(self):
return self.request.parser_context.get('kwargs').get('pk')
class RecursiveFieldSerializer(serializers.Serializer):
def to_representation(self, value):
serializer = self.parent.parent.__class__(value, context=self.context)

View File

@ -0,0 +1,19 @@
"""Overridden thumbnail engine."""
from sorl.thumbnail.engines.pil_engine import Engine as PILEngine
class GMEngine(PILEngine):
def create(self, image, geometry, options):
"""
Processing conductor, returns the thumbnail as an image engine instance
"""
image = self.cropbox(image, geometry, options)
image = self.orientation(image, geometry, options)
image = self.colorspace(image, geometry, options)
image = self.remove_border(image, options)
image = self.crop(image, geometry, options)
image = self.rounded(image, geometry, options)
image = self.blur(image, geometry, options)
image = self.padding(image, geometry, options)
return image

View File

@ -70,22 +70,12 @@ class JWTGenericViewMixin:
def _put_cookies_in_response(self, cookies: list, response: Response):
"""Update COOKIES in response from namedtuple"""
for cookie in cookies:
# todo: remove config for develop
from os import environ
configuration = environ.get('SETTINGS_CONFIGURATION', None)
if configuration == 'development' or configuration == 'stage':
response.set_cookie(key=cookie.key,
value=cookie.value,
secure=cookie.secure,
httponly=cookie.http_only,
max_age=cookie.max_age,
domain='.id-east.ru')
else:
response.set_cookie(key=cookie.key,
value=cookie.value,
secure=cookie.secure,
httponly=cookie.http_only,
max_age=cookie.max_age,)
response.set_cookie(key=cookie.key,
value=cookie.value,
secure=cookie.secure,
httponly=cookie.http_only,
max_age=cookie.max_age,
domain=settings.COOKIE_DOMAIN)
return response
def _get_tokens_from_cookies(self, request, cookies: dict = None):
@ -126,9 +116,8 @@ class CreateDestroyGalleryViewMixin(generics.CreateAPIView,
return Response(status=status.HTTP_204_NO_CONTENT)
class FavoritesCreateDestroyMixinView(generics.CreateAPIView,
generics.DestroyAPIView):
"""Favorites Create Destroy mixin."""
class BaseCreateDestroyMixinView(generics.CreateAPIView, generics.DestroyAPIView):
"""Base Create Destroy mixin."""
_model = None
serializer_class = None
@ -137,16 +126,6 @@ class FavoritesCreateDestroyMixinView(generics.CreateAPIView,
def get_base_object(self):
return get_object_or_404(self._model, slug=self.kwargs['slug'])
def get_object(self):
"""
Returns the object the view is displaying.
"""
obj = self.get_base_object()
favorites = get_object_or_404(obj.favorites.filter(user=self.request.user))
# May raise a permission denied
self.check_object_permissions(self.request, favorites)
return favorites
def es_update_base_object(self):
es_update(self.get_base_object())
@ -159,6 +138,40 @@ class FavoritesCreateDestroyMixinView(generics.CreateAPIView,
self.es_update_base_object()
class FavoritesCreateDestroyMixinView(BaseCreateDestroyMixinView):
"""Favorites Create Destroy mixin."""
def get_object(self):
"""
Returns the object the view is displaying.
"""
obj = self.get_base_object()
favorites = get_object_or_404(obj.favorites.filter(user=self.request.user))
# May raise a permission denied
self.check_object_permissions(self.request, favorites)
return favorites
class CarouselCreateDestroyMixinView(BaseCreateDestroyMixinView):
"""Carousel Create Destroy mixin."""
lookup_field = 'id'
def get_base_object(self):
return get_object_or_404(self._model, id=self.kwargs['pk'])
def get_object(self):
"""
Returns the object the view is displaying.
"""
obj = self.get_base_object()
carousels = get_object_or_404(obj.carousels.all())
# May raise a permission denied
# TODO: возможно нужны пермишены
# self.check_object_permissions(self.request, carousels)
return carousels
# BackOffice user`s views & viewsets
class BindObjectMixin:
"""Bind object mixin."""

View File

@ -1,23 +0,0 @@
#!/bin/bash
DB_CITY_URL="https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz"
DB_COUNTRY_URL="https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz"
DIR_PATH="geoip_db"
ARCH_PATH="archive"
mkdir -p $DIR_PATH
cd $DIR_PATH
mkdir -p $ARCH_PATH
find . -not -path "./$ARCH_PATH/*" -type f -name "*.mmdb" -exec mv -t "./$ARCH_PATH/" {} \+
filename=$(basename $DB_CITY_URL)
wget -O $filename $DB_CITY_URL
tar xzvf "$filename"
filename=$(basename $DB_COUNTRY_URL)
wget -O $filename $DB_COUNTRY_URL
tar xzvf "$filename"
find . -mindepth 1 -type f -name "*.mmdb" -not -path "./$ARCH_PATH/*" -exec mv -t . {} \+

14
make_data_migration.sh Executable file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
./manage.py transfer -a
#./manage.py transfer -d
./manage.py transfer -e
./manage.py transfer --fill_city_gallery
./manage.py transfer -l
./manage.py transfer --product
./manage.py transfer --souvenir
./manage.py transfer --establishment_note
./manage.py transfer --product_note
./manage.py transfer --wine_characteristics
./manage.py transfer --inquiries
./manage.py transfer --assemblage
./manage.py transfer --purchased_plaques

View File

@ -13,9 +13,9 @@ AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'}
AWS_S3_ADDRESSING_STYLE = 'path'
# Static settings
# PUBLIC_STATIC_LOCATION = 'static'
# STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{PUBLIC_STATIC_LOCATION}/'
# STATICFILES_STORAGE = 'project.storage_backends.PublicStaticStorage'
PUBLIC_STATIC_LOCATION = 'static-dev'
STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{PUBLIC_STATIC_LOCATION}/'
STATICFILES_STORAGE = 'project.storage_backends.PublicStaticStorage'
# Public media settings
MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{MEDIA_LOCATION}/'

View File

@ -399,6 +399,13 @@ SORL_THUMBNAIL_ALIASES = {
'establishment_xlarge': {'geometry_string': '640x360', 'crop': 'center'},
'establishment_detail': {'geometry_string': '2048x1152', 'crop': 'center'},
'establishment_original': {'geometry_string': '1920x1080', 'crop': 'center'},
'city_xsmall': {'geometry_string': '70x70', 'crop': 'center'},
'city_small': {'geometry_string': '140x140', 'crop': 'center'},
'city_medium': {'geometry_string': '280x280', 'crop': 'center'},
'city_large': {'geometry_string': '280x280', 'crop': 'center'},
'city_xlarge': {'geometry_string': '560x560', 'crop': 'center'},
'city_detail': {'geometry_string': '1120x1120', 'crop': 'center'},
'city_original': {'geometry_string': '2048x1536', 'crop': 'center'},
}
@ -487,7 +494,6 @@ LIMITING_QUERY_OBJECTS = QUERY_OUTPUT_OBJECTS * 3
# GEO
# A Spatial Reference System Identifier
GEO_DEFAULT_SRID = 4326
GEOIP_PATH = os.path.join(PROJECT_ROOT, 'geoip_db')
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
@ -514,3 +520,6 @@ ESTABLISHMENT_CHOSEN_TAGS = ['gastronomic', 'en_vogue', 'terrace', 'streetfood',
NEWS_CHOSEN_TAGS = ['eat', 'drink', 'cook', 'style', 'international', 'event', 'partnership']
INTERNATIONAL_COUNTRY_CODES = ['www', 'main', 'next']
THUMBNAIL_ENGINE = 'utils.thumbnail_engine.GMEngine'
COOKIE_DOMAIN = None

View File

@ -18,6 +18,17 @@ SITE_DOMAIN_URI = 'id-east.ru'
DOMAIN_URI = 'gm.id-east.ru'
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
},
'es_queue': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://localhost:6379/2'
}
}
# ELASTICSEARCH SETTINGS
ELASTICSEARCH_DSL = {
'default': {
@ -60,3 +71,5 @@ INSTALLED_APPS.append('transfer.apps.TransferConfig')
BROKER_URL = 'redis://localhost:6379/1'
CELERY_RESULT_BACKEND = BROKER_URL
CELERY_BROKER_URL = BROKER_URL
COOKIE_DOMAIN = '.id-east.ru'

View File

@ -5,18 +5,15 @@ import sys
ALLOWED_HOSTS = ['*', ]
SEND_SMS = False
SMS_CODE_SHOW = True
USE_CELERY = True
SCHEMA_URI = 'http'
DEFAULT_SUBDOMAIN = 'www'
SITE_DOMAIN_URI = 'testserver.com:8000'
DOMAIN_URI = '0.0.0.0:8000'
# CELERY
# RabbitMQ
# BROKER_URL = 'amqp://rabbitmq:5672'
@ -25,20 +22,16 @@ BROKER_URL = 'redis://redis:6379/1'
CELERY_RESULT_BACKEND = BROKER_URL
CELERY_BROKER_URL = BROKER_URL
# MEDIA
MEDIA_URL = f'{SCHEMA_URI}://{DOMAIN_URI}/{MEDIA_LOCATION}/'
MEDIA_ROOT = os.path.join(PUBLIC_ROOT, MEDIA_LOCATION)
# SORL thumbnails
THUMBNAIL_DEBUG = True
# ADDED TRANSFER APP
# INSTALLED_APPS.append('transfer.apps.TransferConfig')
# DATABASES
DATABASES.update({
'legacy': {
@ -80,15 +73,14 @@ LOGGING = {
'py.warnings': {
'handlers': ['console'],
},
'django.db.backends': {
'handlers': ['console', ],
'level': 'DEBUG',
'propagate': False,
},
# 'django.db.backends': {
# 'handlers': ['console', ],
# 'level': 'DEBUG',
# 'propagate': False,
# },
}
}
# ELASTICSEARCH SETTINGS
ELASTICSEARCH_DSL = {
'default': {
@ -103,7 +95,7 @@ ELASTICSEARCH_INDEX_NAMES = {
}
ELASTICSEARCH_DSL_AUTOSYNC = False
TESTING = sys.argv[1:2] == ['test']
if TESTING:
ELASTICSEARCH_INDEX_NAMES = {}
ELASTICSEARCH_DSL_AUTOSYNC = False

View File

@ -4,6 +4,11 @@ from .amazon_s3 import *
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
PUBLIC_STATIC_LOCATION = 'static'
STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{PUBLIC_STATIC_LOCATION}/'
STATICFILES_STORAGE = 'project.storage_backends.PublicStaticStorage'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
@ -20,7 +25,6 @@ DEFAULT_SUBDOMAIN = 'www'
SITE_DOMAIN_URI = 'gaultmillau.com'
DOMAIN_URI = 'next.gaultmillau.com'
# ELASTICSEARCH SETTINGS
ELASTICSEARCH_DSL = {
'default': {
@ -28,20 +32,17 @@ ELASTICSEARCH_DSL = {
}
}
ELASTICSEARCH_INDEX_NAMES = {
'search_indexes.documents.news': 'development_news', # temporarily disabled
'search_indexes.documents.establishment': 'development_establishment',
'search_indexes.documents.product': 'development_product',
}
sentry_sdk.init(
dsn="https://35d9bb789677410ab84a822831c6314f@sentry.io/1729093",
integrations=[DjangoIntegration()]
)
BROKER_URL = 'redis://redis:6379/1'
CELERY_RESULT_BACKEND = BROKER_URL
CELERY_BROKER_URL = BROKER_URL
@ -51,4 +52,6 @@ GUESTONLINE_SERVICE = 'https://api.guestonline.fr/'
GUESTONLINE_TOKEN = ''
LASTABLE_SERVICE = ''
LASTABLE_TOKEN = ''
LASTABLE_PROXY = ''
LASTABLE_PROXY = ''
COOKIE_DOMAIN = '.gaultmillau.com'

View File

@ -13,7 +13,6 @@ DEFAULT_SUBDOMAIN = 'www'
SITE_DOMAIN_URI = 'id-east.ru'
DOMAIN_URI = 'gm-stage.id-east.ru'
# ELASTICSEARCH SETTINGS
ELASTICSEARCH_DSL = {
'default': {
@ -21,8 +20,9 @@ ELASTICSEARCH_DSL = {
}
}
ELASTICSEARCH_INDEX_NAMES = {
# 'search_indexes.documents.news': 'stage_news', #temporarily disabled
'search_indexes.documents.establishment': 'stage_establishment',
}
COOKIE_DOMAIN = '.id-east.ru'