Merge branch 'develop' into features/migrate-wine

# Conflicts:
#	apps/product/models.py
#	apps/transfer/management/commands/transfer.py
#	apps/transfer/models.py
This commit is contained in:
Anatoly 2019-11-05 14:56:26 +03:00
commit d46ba31654
88 changed files with 1961 additions and 450 deletions

View File

@ -113,7 +113,7 @@ class OAuth2SignUpView(OAuth2ViewMixin, JWTGenericViewMixin):
# Check OAuth2 response
if oauth2_status != status.HTTP_200_OK:
raise utils_exceptions.OAuth2Error()
raise utils_exceptions.OAuth2Error(detail=body)
# Get authenticated user
user = User.objects.by_oauth2_access_token(token=body.get('access_token'))\

View File

@ -0,0 +1,23 @@
# Generated by Django 2.2.4 on 2019-10-25 16:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('booking', '0002_auto_20191003_1601'),
]
operations = [
migrations.AddField(
model_name='booking',
name='amount',
field=models.CharField(default=None, max_length=30, null=True, verbose_name='prepayment price'),
),
migrations.AddField(
model_name='booking',
name='stripe_key',
field=models.TextField(default=None, null=True, verbose_name='stripe service payment key'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-10-25 16:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('booking', '0003_auto_20191025_1613'),
]
operations = [
migrations.AddField(
model_name='booking',
name='stripe_token',
field=models.TextField(default=None, null=True, verbose_name='stripe service pre-payed booking token'),
),
]

View File

@ -24,6 +24,9 @@ class Booking(ProjectBaseMixin):
pending_booking_id = models.TextField(verbose_name=_('external service pending booking'), default=None)
booking_id = models.TextField(verbose_name=_('external service booking id'), default=None, null=True,
db_index=True, )
stripe_key = models.TextField(null=True, default=None, verbose_name=_('stripe service payment key'))
stripe_token = models.TextField(null=True, default=None, verbose_name=_('stripe service pre-payed booking token'))
amount = models.CharField(null=True, default=None, verbose_name=_('prepayment price'), max_length=30)
user = models.ForeignKey(
'account.User', verbose_name=_('booking owner'), null=True,
related_name='bookings',

View File

@ -1,10 +1,13 @@
from abc import ABC, abstractmethod
import json
from abc import ABC, abstractmethod
import requests
from django.conf import settings
from rest_framework import status
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers, status
from rest_framework.response import Response
import booking.models.models as models
from rest_framework import serializers
class AbstractBookingService(ABC):
@ -24,8 +27,14 @@ class AbstractBookingService(ABC):
self.url = settings.LASTABLE_SERVICE
@staticmethod
def get_certain_keys(d: dict, keys_to_preserve: set) -> dict:
def get_certain_keys(d: dict, keys_to_preserve: set, required: set = {}, check: bool = True) -> dict:
""" Helper """
if len(required) == 0 and check:
required = keys_to_preserve.copy()
if required and check:
diff = required - d.keys()
if diff:
raise serializers.ValidationError({field: _(f'This field is required') for field in diff})
return {key: d[key] for key in d.keys() & keys_to_preserve}
@abstractmethod
@ -66,22 +75,22 @@ class GuestonlineService(AbstractBookingService):
def get_common_headers(self):
return {'X-Token': self.token, 'Content-type': 'application/json', 'Accept': 'application/json'}
def check_whether_booking_available(self, restaurant_id, date: str):
super().check_whether_booking_available(restaurant_id, date)
url = f'{self.url}v1/runtime_services'
params = {'restaurant_id': restaurant_id, 'date': date, 'expands[]': 'table_availabilities'}
def check_whether_booking_available(self, restaurant_id, *args, **kwargs):
url = f'{self.url}v1/periods'
params = {'restaurant_id': restaurant_id, **kwargs}
r = requests.get(url, headers=self.get_common_headers(), params=params)
if not status.is_success(r.status_code):
return False
response = json.loads(r.content)['runtime_services']
keys_to_preserve = {'left_seats', 'table_availabilities', 'closed', 'start_time', 'end_time', 'last_booking'}
response = map(lambda x: self.get_certain_keys(x, keys_to_preserve), response)
self.response = response
self.response = r.json()
return True
def commit_booking(self, payload):
def commit_booking(self, payload, stripe_token = None):
url = f'{self.url}v1/pending_bookings/{payload}/commit'
r = requests.put(url, headers=self.get_common_headers())
if stripe_token:
r = requests.put(url, headers=self.get_common_headers(),
data=json.dumps({'stripe_token': stripe_token}))
else:
r = requests.put(url, headers=self.get_common_headers())
self.response = json.loads(r.content)
if status.is_success(r.status_code) and self.response is None:
raise serializers.ValidationError(detail='Booking already committed.')
@ -93,8 +102,13 @@ class GuestonlineService(AbstractBookingService):
payload['lastname'] = payload.pop('last_name')
payload['firstname'] = payload.pop('first_name')
payload['mobile_phone'] = payload.pop('phone')
payload['user_locale'] = payload.pop('country_code')
headers = self.get_common_headers()
r = requests.put(url, headers=headers, data=json.dumps({'contact_info': payload}))
response = r.json()
self.response = response.get('prepayment')
if not status.is_success(r.status_code):
return Response(status=r.status_code, data=response)
return status.is_success(r.status_code)
def create_booking(self, payload):
@ -103,7 +117,10 @@ class GuestonlineService(AbstractBookingService):
payload['persons'] = payload.pop('booked_persons_number')
payload['date'] = payload.pop('booking_date')
r = requests.post(url, headers=self.get_common_headers(), data=json.dumps(payload))
return json.loads(r.content)['id'] if status.is_success(r.status_code) else False
if status.is_success(r.status_code):
return json.loads(r.content)['id']
else:
return Response(status=r.status_code, data=r.json())
def cancel_booking(self, payload):
url = f'{self.url}v1/pending_bookings/{payload}'

View File

@ -42,13 +42,29 @@ class PendingBookingSerializer(serializers.ModelSerializer):
'user',
)
class CommitBookingSerializer(serializers.ModelSerializer):
class Meta:
model = models.Booking
fields = (
'stripe_token',
)
def update(self, instance, validated_data):
"""Override update method"""
# Update user password from instance
service = instance.get_service_by_type(instance.type)
service.commit_booking(instance.pending_booking_id, validated_data.get('stripe_token'))
instance.stripe_token = validated_data.get('stripe_token')
instance.save()
return instance
class UpdateBookingSerializer(serializers.ModelSerializer):
id = serializers.ReadOnlyField()
class Meta:
model = models.Booking
fields = ('booking_id', 'id')
fields = ('booking_id', 'id', 'stripe_key', 'amount')
class GetBookingSerializer(serializers.ModelSerializer):

View File

@ -8,6 +8,7 @@ urlpatterns = [
path('<int:establishment_id>/check/', views.CheckWhetherBookingAvailable.as_view(), name='booking-check'),
path('<int:establishment_id>/create/', views.CreatePendingBooking.as_view(), name='create-pending-booking'),
path('<int:pk>/', views.UpdatePendingBooking.as_view(), name='update-pending-booking'),
path('<int:pk>/commit/', views.CommitPendingBooking.as_view(), name='update-pending-booking'),
path('<int:pk>/cancel/', views.CancelBooking.as_view(), name='cancel-existing-booking'),
path('last/', views.LastBooking.as_view(), name='last_booking-for-authorizer-user'),
path('retrieve/<int:pk>/', views.GetBookingById.as_view(), name='retrieves-booking-by-id'),

View File

@ -1,11 +1,13 @@
from rest_framework import generics, permissions, status, serializers
from django.shortcuts import get_object_or_404
from establishment.models import Establishment
from booking.models.models import Booking, GuestonlineService, LastableService
from rest_framework import generics, permissions, status, serializers
from rest_framework.response import Response
from booking.serializers.web import (PendingBookingSerializer,
UpdateBookingSerializer, GetBookingSerializer, CheckBookingSerializer)
from booking.models.models import Booking, GuestonlineService, LastableService
from booking.serializers.web import (PendingBookingSerializer, UpdateBookingSerializer, GetBookingSerializer,
CheckBookingSerializer, CommitBookingSerializer)
from establishment.models import Establishment
from notification.models import Subscriber
from utils.methods import get_user_ip
class CheckWhetherBookingAvailable(generics.GenericAPIView):
@ -28,7 +30,9 @@ class CheckWhetherBookingAvailable(generics.GenericAPIView):
service = l_service
service.service_id = establishment.lastable_id
elif (not establishment.guestonline_id is None) and g_service \
.check_whether_booking_available(establishment.guestonline_id, date):
.check_whether_booking_available(establishment.guestonline_id,
**g_service.get_certain_keys(request.query_params,
{'date', 'persons'})):
is_booking_available = True
service = g_service
service.service_id = establishment.guestonline_id
@ -61,7 +65,9 @@ class CreatePendingBooking(generics.CreateAPIView):
}
data['pending_booking_id'] = service.create_booking(
service.get_certain_keys(data.copy(), service_to_keys[data.get('type')]))
if not data['pending_booking_id']:
if isinstance(data['pending_booking_id'], Response):
return data['pending_booking_id']
elif not data['pending_booking_id']:
return Response(status=status.HTTP_403_FORBIDDEN, data='Unable to create booking')
data['booking_id'] = data['pending_booking_id'] if data.get('type') == Booking.LASTABLE else None
serializer = self.get_serializer(data=data)
@ -70,6 +76,13 @@ class CreatePendingBooking(generics.CreateAPIView):
return Response(status=status.HTTP_201_CREATED, data=serializer.data)
class CommitPendingBooking(generics.UpdateAPIView):
""" Commit pending booking """
queryset = Booking.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = CommitBookingSerializer
class UpdatePendingBooking(generics.UpdateAPIView):
""" Update pending booking with contacts """
queryset = Booking.objects.all()
@ -81,9 +94,31 @@ class UpdatePendingBooking(generics.UpdateAPIView):
data = request.data.copy()
service = Booking.get_service_by_type(instance.type)
data['pending_booking_id'] = instance.pending_booking_id
service.update_booking(service.get_certain_keys(data, {
r = service.update_booking(service.get_certain_keys(data, {
'email', 'phone', 'last_name', 'first_name', 'country_code', 'pending_booking_id', 'note',
}, {
'email', 'phone', 'last_name', 'first_name', 'country_code', 'pending_booking_id',
}))
if isinstance(r, Response):
return r
if data.get('newsletter'):
Subscriber.objects.make_subscriber(email=data['email'], country_code=data['country_code'],
locale=request.locale, ip_address=get_user_ip(request),
user=None if request.user.is_anonymous else request.user)
if service.response:
# если есть предоплата, возвращаем фронту страйп-ключ для совершения оплаты и цену
amount = service.response.get('amount')
stripe_key = service.response.get('stripe_key')
data = {
'id': instance.pk,
'amount': amount,
'stripe_key': stripe_key,
'type': instance.type,
}
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.update(instance, data)
return Response(status=status.HTTP_200_OK, data=data)
service.commit_booking(data['pending_booking_id'])
data = {
'booking_id': service.response.get('id'),

View File

View File

@ -0,0 +1,169 @@
from django.core.management.base import BaseCommand
from establishment.models import Establishment
from location.models import Country, Language
from transfer.models import Collections
from collection.models import Collection
from news.models import News
class Command(BaseCommand):
help = 'Import collection'
def handle(self, *args, **kwargs):
raw_qs = Collections.objects.raw('''
select
distinct
a.id,
a.collection_id,
-- a.establishment_id,
a.title,
a.tag_name,
a.slug,
-- a.attachment_file_name,
-- a.attachment_content_type,
-- a.attachment_file_size,
a.attachment_suffix_url,
-- active as is_publish,
a.country_code,
-- a.geometries,
a.description,
min(a.start) AS start
from
(
select distinct
c.id,
c.id as collection_id,
m.establishment_id,
c.title, c.tag_name,
c.slug, c.attachment_file_name,
c.attachment_content_type, c.attachment_file_size,
c.attachment_suffix_url,
active,
s.country_code_2 as country_code,
c.geometries,
c.title as description,
m.created_at as start
from collections as c
join metadata m on m.value = c.tag_name
join establishments e on e.id = m.establishment_id
join sites s on s.id = c.site_id
where m.`key` = 'collection'
union
select distinct
c.id,
c.id as collection_id,
m.establishment_id,
c.title, c.tag_name,
c.slug, c.attachment_file_name,
c.attachment_content_type, c.attachment_file_size,
c.attachment_suffix_url,
active,
s.country_code_2 as country_code,
c.geometries,
c.title as description,
m.created_at as start
from collections as c
join metadata m on m.value = c.slug
join establishments e on e.id = m.establishment_id
join sites s on s.id = c.site_id
where m.`key` = 'collection'
) a
group by
a.id,
a.collection_id,
-- a.establishment_id,
a.title,
a.tag_name,
a.slug,
-- a.attachment_file_name,
-- a.attachment_content_type,
-- a.attachment_file_size,
a.attachment_suffix_url,
-- active as is_publish,
a.country_code,
a.description
''')
objects = []
queryset = [vars(query) for query in raw_qs]
for obj in queryset:
# establishment = Establishment.objects.filter(old_id=obj['establishment_id']).first()
# lang = Language.objects.filter(locale=obj['country_code'])
country = Country.objects.filter(code=obj['country_code']).first()
if country:
objects.append(
Collection(name={"en-GB": obj['title']}, collection_type=Collection.ORDINARY,
country=country,
description=obj['description'],
slug=obj['slug'], old_id=obj['collection_id'],
start=obj['start'],
image_url='https://s3.eu-central-1.amazonaws.com/gm-test.com/media/'+obj['attachment_suffix_url']
)
)
Collection.objects.bulk_create(objects)
raw_qs = Collections.objects.raw('''
select
distinct
a.id,
a.collection_id,
a.establishment_id,
a.active
from
(
select distinct
c.id,
c.id as collection_id,
m.establishment_id,
c.title, c.tag_name,
c.slug, c.attachment_file_name,
c.attachment_content_type, c.attachment_file_size,
c.attachment_suffix_url,
active,
s.country_code_2 as country_code,
c.geometries,
c.title as description,
m.created_at as start
from collections as c
join metadata m on m.value = c.tag_name
join establishments e on e.id = m.establishment_id
join sites s on s.id = c.site_id
where m.`key` = 'collection'
union
select distinct
c.id,
c.id as collection_id,
m.establishment_id,
c.title, c.tag_name,
c.slug, c.attachment_file_name,
c.attachment_content_type, c.attachment_file_size,
c.attachment_suffix_url,
active,
s.country_code_2 as country_code,
c.geometries,
c.title as description,
m.created_at as start
from collections as c
join metadata m on m.value = c.slug
join establishments e on e.id = m.establishment_id
join sites s on s.id = c.site_id
where m.`key` = 'collection'
) a
''')
queryset = [vars(query) for query in raw_qs]
for obj in queryset:
print('COLLECT_ID: {}'.format(obj['collection_id']))
est = Establishment.objects.filter(old_id=obj['establishment_id'])
if est.exists():
inst = est.first()
collect = Collection.objects.filter(old_id=obj['collection_id'])
collect.update(is_publish=obj['active'])
print(f'COLLECT COUNT {collect.count()}')
inst.collections.add(*list(collect))
# for c in collect:
# inst.collections.add(c)
inst.save()

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-10-31 13:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('collection', '0016_auto_20191024_1334'),
]
operations = [
migrations.AddField(
model_name='collection',
name='old_id',
field=models.IntegerField(blank=True, null=True),
),
]

View File

@ -76,6 +76,7 @@ class Collection(ProjectBaseMixin, CollectionDateMixin,
slug = models.SlugField(max_length=50, unique=True,
verbose_name=_('Collection slug'), editable=True, null=True)
old_id=models.IntegerField(null=True, blank=True)
objects = CollectionQuerySet.as_manager()
class Meta:

View File

@ -1,112 +0,0 @@
import json
import pytz
from datetime import datetime
from http.cookies import SimpleCookie
from rest_framework import status
from rest_framework.test import APITestCase
from account.models import User
from collection.models import Collection, Guide
from establishment.models import Establishment, EstablishmentType
from location.models import Country
class BaseTestCase(APITestCase):
def setUp(self):
self.username = 'sedragurda'
self.password = 'sedragurdaredips19'
self.email = 'sedragurda@desoz.com'
self.newsletter = True
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'),
'country_code': 'en'})
class CollectionListTests(BaseTestCase):
def test_collection_list_Read(self):
response = self.client.get('/api/web/collections/', format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
class CollectionDetailTests(BaseTestCase):
def setUp(self):
super().setUp()
# country = Country.objects.first()
# if not country:
country = Country.objects.create(
name=json.dumps({"en-GB": "Test country"}),
code="en"
)
country.save()
self.collection = Collection.objects.create(
name='Test collection',
is_publish=True,
start=datetime.now(pytz.utc),
end=datetime.now(pytz.utc),
country=country,
slug='test-collection-slug',
)
self.collection.save()
def test_collection_detail_Read(self):
response = self.client.get(f'/api/web/collections/{self.collection.slug}/establishments/?country_code=en',
format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
class CollectionGuideTests(CollectionDetailTests):
def test_guide_list_Read(self):
response = self.client.get('/api/web/collections/guides/', format='json')
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
class CollectionGuideDetailTests(CollectionDetailTests):
def setUp(self):
super().setUp()
self.guide = Guide.objects.create(
collection=self.collection,
start=datetime.now(pytz.utc),
end=datetime.now(pytz.utc)
)
self.guide.save()
def test_guide_detail_Read(self):
response = self.client.get(f'/api/web/collections/guides/{self.guide.id}/', format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
class CollectionWebHomeTests(CollectionDetailTests):
def setUp(self):
super().setUp()
self.establishment_type = EstablishmentType.objects.create(name="Test establishment type")
for i in range(1, 5):
setattr(self, f"establishment{i}",
Establishment.objects.create(
name=f"Test establishment {i}",
establishment_type_id=self.establishment_type.id,
is_publish=True,
slug=f"test-establishment-{i}"
)
)
getattr(self, f"establishment{i}").collections.add(self.collection)
def test_collection_list_filter(self):
response = self.client.get('/api/web/collections/?country_code=en', format='json')
data = response.json()
self.assertIn('count', data)
self.assertGreater(data['count'], 0)

View File

@ -1,48 +0,0 @@
"""
Структура fields:
key - поле в таблице postgres
value - поле или группа полей в таблице legacy
В случае передачи группы полей каждое поле представляет собой кортеж, где:
field[0] - название аргумента
field[1] - название поля в таблице legacy
Опционально: field[2] - тип данных для преобразования
"""
card = {
"Collection": {
"data_type": "objects",
"dependencies": ("Country", ),
"fields": {
"Collections": {
# нету аналогов для полей description, start и end
"name": "title",
"slug": "slug",
"block_size": ("geometries", "django.db.models.JSONField"),
"is_publish": ("active", "django.db.models.BooleanField"),
"image_url": ("attachment_file_name", "django.db.models.URLField")
}
},
"relations": {
# "country": "Country",
}
},
"Guide": {
# как работать с ForeignKey на самого себя(self), поле "parent"
"data_type": "objects",
"dependencies": ("Collection", "self"),
"fields": {
"Guides": {
# нету аналогов для полей start и end
"name": "title"
}
},
"relations": {
# аналалог для поля "collection" не найдено
# "parent": "Guide",
# "collection": "Collection"
}
}
}
used_apps = ("location", )

View File

@ -57,9 +57,10 @@ class ProductInline(admin.TabularInline):
class EstablishmentAdmin(BaseModelAdminMixin, admin.ModelAdmin):
"""Establishment admin."""
list_display = ['id', '__str__', 'image_tag', ]
inlines = [
AwardInline, ContactPhoneInline, ContactEmailInline,
ReviewInline, CommentInline, ProductInline]
# inlines = [
# AwardInline, ContactPhoneInline, ContactEmailInline,
# ReviewInline, CommentInline, ProductInline]
raw_id_fields = ('address',)
@ -78,6 +79,7 @@ class PlateInline(admin.TabularInline):
class MenuAdmin(BaseModelAdminMixin, admin.ModelAdmin):
"""Menu admin."""
list_display = ['id', 'category_translated']
raw_id_fields = ['establishment']
inlines = [
PlateInline,
]
@ -87,3 +89,8 @@ class MenuAdmin(BaseModelAdminMixin, admin.ModelAdmin):
return obj.category_translated
category_translated.short_description = _('category')
@admin.register(models.RatingStrategy)
class RatingStrategyAdmin(BaseModelAdminMixin, admin.ModelAdmin):
"""Admin conf for Rating Strategy model."""

View File

@ -0,0 +1,40 @@
from django.core.management.base import BaseCommand
import requests
from establishment.models import Establishment
from main.models import Currency
from location.models import Country
from django.template.defaultfilters import slugify
class Command(BaseCommand):
help = 'Add currency to new db'
def handle(self, *args, **kwargs):
count = 0
url = 'https://restcountries.eu/rest/v2/name/{country}'
countries = Country.objects.all()
for country in countries:
country_name = country.name["en-GB"]
resp = requests.get(url=url.format(country=country_name))
if resp.status_code == requests.codes.ok:
country_list = resp.json()
if isinstance(country_list, list):
currency_dict = country_list[0].get("currencies")[0]
if currency_dict:
name = currency_dict['name']
if name:
slug = slugify(name)
currency, _ = Currency.objects.get_or_create(
slug=slug,
)
currency.name = {"en-GB": name}
currency.sign = currency_dict["symbol"]
currency.save()
establishments = Establishment.objects.filter(address__city__country=country)
establishments.update(currency=currency)
count += 1
self.stdout.write(self.style.WARNING(f'Created/updated {count} objects.'))

View File

@ -1,31 +1,67 @@
from django.core.management.base import BaseCommand
from establishment.models import Establishment
from transfer.models import Descriptions
from transfer.models import Reviews, ReviewTexts
class Command(BaseCommand):
help = 'Add description values from old db to new db'
help = 'Add description values from old db reviews to new db'
def handle(self, *args, **kwargs):
count = 0
update_locale = 0
valid_reviews = {}
queryset = Descriptions.objects.all()
for obj in queryset:
queryset = Reviews.objects.exclude(
establishment_id__isnull=True
).filter(
aasm_state='published'
).values_list(
'id',
'establishment_id',
'updated_at',
)
for r_id, establishment_id, new_date in queryset:
try:
establishment = Establishment.objects.get(old_id=obj.establishment.id)
except Establishment.DoesNotExist:
continue
except Establishment.MultipleObjectsReturned:
establishment = Establishment.objects.filter(old_id=obj.establishment.id).first()
review_id, date = valid_reviews[establishment_id]
except KeyError:
valid_reviews[establishment_id] = (r_id, new_date)
else:
if new_date > date:
valid_reviews[establishment_id] = (r_id, new_date)
text_qs = ReviewTexts.objects.exclude(
locale__isnull=True
).filter(
review_id__in=(value[0] for value in valid_reviews.values()),
).values_list(
'review__establishment_id',
'locale',
'text',
)
for es_id, locale, text in text_qs:
establishment = Establishment.objects.filter(old_id=es_id).first()
if establishment:
description = establishment.description
description.update({
obj.locale: obj.text
locale: text
})
establishment.description = description
establishment.save()
count += 1
break
# Если нет en-GB в поле
for establishment in Establishment.objects.filter(old_id__isnull=False):
description = establishment.description
if len(description) and 'en-GB' not in description:
description.update({
'en-GB': next(iter(description.values()))
})
establishment.description = description
establishment.save()
update_locale += 1
self.stdout.write(self.style.WARNING(f'Updated {count} objects.'))
self.stdout.write(self.style.WARNING(f'Updated en-GB locale - {count}'))

View File

@ -18,14 +18,16 @@ class Command(BaseCommand):
AND scope = 'public'
AND type = 'Photo'
AND menu_id IS NULL
GROUP BY establishment_id;'''
GROUP BY establishment_assets.id, establishment_id, attachment_suffix_url;'''
)
queryset = [vars(query) for query in raw_qs]
for obj in queryset:
establishment = Establishment.objects.filter(old_id=obj['establishment_id']).first()
establishment = Establishment.objects.filter(old_id=obj['establishment_id'], image_url__isnull=True).first()
if establishment:
img = url + obj['attachment_suffix_url']
establishment.preview_image_url = img
img_url = img[:-12]
extension = img.split('.')[-1:][0] # JPG
establishment.preview_image_url = f'{img_url}xlarge.{extension}'
establishment.image_url = img
establishment.save()
count += 1

View File

@ -0,0 +1,56 @@
from django.core.management.base import BaseCommand
from establishment.models import Establishment, SocialNetwork
from transfer.models import EstablishmentInfos
class Command(BaseCommand):
help = 'Add social links values from old db to new db'
def handle(self, *args, **kwargs):
count = 0
queryset = EstablishmentInfos.objects.exclude(
establishment_id__isnull=True
).values_list('id', 'establishment_id', 'facebook', 'twitter', 'instagram')
for id, es_id, facebook, twitter, instagram in queryset:
try:
establishment = Establishment.objects.get(old_id=es_id)
except Establishment.DoesNotExist:
continue
except Establishment.MultipleObjectsReturned:
establishment = Establishment.objects.filter(old_id=es_id).first()
else:
if facebook:
if 'facebook.com/' not in facebook:
facebook = 'https://www.facebook.com/' + facebook
obj, _ = SocialNetwork.objects.get_or_create(
old_id=id,
establishment=establishment,
title='facebook',
url=facebook,
)
count += 1
if twitter:
if 'twitter.com/' not in twitter:
twitter = 'https://www.twitter.com/' + twitter
obj, _ = SocialNetwork.objects.get_or_create(
old_id=id,
establishment=establishment,
title='twitter',
url=twitter,
)
count += 1
if instagram:
if 'instagram.com/' not in instagram:
instagram = 'https://www.instagram.com/' + instagram
obj, _ = SocialNetwork.objects.get_or_create(
old_id=id,
establishment=establishment,
title='instagram',
url=instagram,
)
count += 1
self.stdout.write(self.style.WARNING(f'Created/updated {count} objects.'))

View File

@ -0,0 +1,33 @@
from django.core.management.base import BaseCommand
from establishment.models import Establishment, Menu, Plate
from transfer.models import Menus
class Command(BaseCommand):
help = 'Add menus from old db to new db'
def handle(self, *args, **kwargs):
count = 0
menus = Menus.objects.filter(name__isnull=False).exclude(name='')
for old_menu in menus:
est = Establishment.objects.filter(
old_id=old_menu.establishment_id).first()
if est:
menu, _ = Menu.objects.get_or_create(
category={'en-GB': 'formulas'},
establishment=est
)
plate, created = Plate.objects.get_or_create(
name={"en-GB": old_menu.name},
menu=menu,
price=old_menu.price or 0
)
if created:
plate.currency_code = old_menu.currency
plate.currency = est.currency
plate.save()
count += 1
self.stdout.write(self.style.WARNING(f'Updated/created {count} objects.'))

View File

@ -0,0 +1,16 @@
"""Run recalculating toque number for establishments."""
from django.core.management.base import BaseCommand
from establishment.models import Establishment
class Command(BaseCommand):
help = 'Recalculation toque number for all establishments.'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def handle(self, *args, **options):
for establishment in Establishment.objects.select_related('address__city__country'):
print(f'Recalculate for {establishment.name} ({establishment.id})')
establishment.recalculate_toque_number()

View File

@ -0,0 +1,30 @@
from django.core.management.base import BaseCommand
from establishment.models import Establishment
from transfer.models import Establishments as OldEst
class Command(BaseCommand):
help = 'Update transportation column in establishment'
def handle(self, *args, **kwargs):
count = 0
raw_qs = OldEst.objects.raw(
'''
select
e.id,
l.transportation
from establishments e
join locations l on l.id = e.location_id
where trim(l.transportation) is not null
and length(trim(l.transportation)) >1;
'''
)
queryset = [vars(query) for query in raw_qs]
for obj in queryset:
establishment = Establishment.objects.filter(old_id=obj['id']).first()
if establishment:
establishment.transportation = obj['transportation']
count += 1
establishment.save()
self.stdout.write(self.style.WARNING(f'Updated {count} objects.'))

View File

@ -0,0 +1,33 @@
# Generated by Django 2.2.4 on 2019-10-31 15:55
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('location', '0020_merge_20191030_1714'),
('establishment', '0047_merge_20191030_1714'),
]
operations = [
migrations.CreateModel(
name='RatingStrategy',
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')),
('toque_number', models.IntegerField(choices=[(1, 'One'), (2, 'Two'), (3, 'Three'), (4, 'Four'), (5, 'Five')])),
('public_mark_min_value', models.IntegerField()),
('public_mark_max_value', models.IntegerField()),
('country', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='location.Country', verbose_name='Country')),
],
options={
'verbose_name': 'Rating strategy',
'verbose_name_plural': 'Rating strategy',
'unique_together': {('country', 'toque_number')},
},
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 2.2.4 on 2019-10-31 16:16
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('establishment', '0048_ratingstrategy'),
]
operations = [
migrations.AlterField(
model_name='ratingstrategy',
name='country',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='location.Country', verbose_name='Country'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-01 07:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('establishment', '0049_auto_20191031_1616'),
]
operations = [
migrations.AddField(
model_name='socialnetwork',
name='old_id',
field=models.PositiveIntegerField(blank=True, default=None, null=True, verbose_name='old id'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-01 07:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('establishment', '0050_socialnetwork_old_id'),
]
operations = [
migrations.AlterField(
model_name='socialnetwork',
name='url',
field=models.URLField(max_length=255, verbose_name='URL'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-03 20:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('establishment', '0051_auto_20191101_0732'),
]
operations = [
migrations.AddField(
model_name='plate',
name='currency_code',
field=models.CharField(blank=True, default=None, max_length=250, null=True, verbose_name='currency code'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 2.2.4 on 2019-11-03 20:51
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('establishment', '0052_plate_currency_code'),
]
operations = [
migrations.AlterField(
model_name='plate',
name='currency',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='main.Currency', verbose_name='currency'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-03 21:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('establishment', '0053_auto_20191103_2051'),
]
operations = [
migrations.AlterField(
model_name='plate',
name='is_signature_plate',
field=models.BooleanField(default=False, verbose_name='is signature plate'),
),
]

View File

@ -14,7 +14,6 @@ from django.db.models import When, Case, F, ExpressionWrapper, Subquery, Q
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from phonenumber_field.modelfields import PhoneNumberField
from pytz import timezone as ptz
from timezone_field import TimeZoneField
from collection.models import Collection
@ -310,6 +309,7 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
public_mark = models.PositiveIntegerField(blank=True, null=True,
default=None,
verbose_name=_('public mark'),)
# todo: set default 0
toque_number = models.PositiveIntegerField(blank=True, null=True,
default=None,
verbose_name=_('toque number'),)
@ -384,7 +384,13 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
# todo: recalculate toque_number
def recalculate_toque_number(self):
self.toque_number = 4
toque_number = 0
if self.address and self.public_mark:
toque_number = RatingStrategy.objects. \
get_toque_number(country=self.address.city.country,
public_mark=self.public_mark)
self.toque_number = toque_number
self.save()
def recalculate_price_level(self, low_price=None, high_price=None):
if low_price is None or high_price is None:
@ -428,6 +434,27 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
def best_price_carte(self):
return 200
@property
def range_price_menu(self):
plates = self.menu_set.filter(
models.Q(category={'en-GB': 'formulas'})
).aggregate(
max=models.Max('plate__price', output_field=models.FloatField()),
min=models.Min('plate__price', output_field=models.FloatField()))
return plates
@property
def range_price_carte(self):
plates = self.menu_set.filter(
models.Q(category={'en-GB': 'starter'}) |
models.Q(category={'en-GB': 'main_course'}) |
models.Q(category={'en-GB': 'dessert'})
).aggregate(
max=models.Max('plate__price', output_field=models.FloatField()),
min=models.Min('plate__price', output_field=models.FloatField()),
)
return plates
@property
def works_noon(self):
""" Used for indexing working by day """
@ -622,9 +649,12 @@ class Plate(TranslatedFieldsMixin, models.Model):
help_text='{"en-GB":"some text"}')
price = models.DecimalField(
_('price'), max_digits=14, decimal_places=2)
is_signature_plate = models.BooleanField(_('is signature plate'))
is_signature_plate = models.BooleanField(_('is signature plate'), default=False)
currency = models.ForeignKey(
'main.Currency', verbose_name=_('currency'), on_delete=models.CASCADE)
'main.Currency', verbose_name=_('currency'), on_delete=models.CASCADE,
blank=True, null=True, default=None)
currency_code = models.CharField(
_('currency code'), max_length=250, blank=True, null=True, default=None)
menu = models.ForeignKey(
'establishment.Menu', verbose_name=_('menu'), on_delete=models.CASCADE)
@ -656,11 +686,12 @@ class Menu(TranslatedFieldsMixin, BaseAttributes):
class SocialNetwork(models.Model):
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
establishment = models.ForeignKey(
'Establishment', verbose_name=_('establishment'),
related_name='socials', on_delete=models.CASCADE)
title = models.CharField(_('title'), max_length=255)
url = models.URLField(_('URL'))
url = models.URLField(_('URL'), max_length=255)
class Meta:
verbose_name = _('social network')
@ -669,3 +700,62 @@ class SocialNetwork(models.Model):
def __str__(self):
return self.title
class RatingStrategyManager(models.Manager):
"""Extended manager for RatingStrategy."""
def get_toque_number(self, country, public_mark):
"""Get toque number for country and public_mark."""
qs = self.model.objects.by_country(country)
if not qs.exists():
qs = self.model.objects.by_country(None)
obj = qs.for_public_mark(public_mark).first()
if obj:
return obj.toque_number
return 0
class RatingStrategyQuerySet(models.QuerySet):
"""Extended queryset for RatingStrategy."""
def by_country(self, country):
"""Filter by country."""
return self.filter(country=country)
def for_public_mark(self, public_mark):
"""Filter for value."""
return self.filter(public_mark_min_value__lte=public_mark,
public_mark_max_value__gte=public_mark)
class RatingStrategy(ProjectBaseMixin):
"""Rating Strategy model."""
TOQUE_NUMBER_CHOICES = (
(1, _('One')),
(2, _('Two')),
(3, _('Three')),
(4, _('Four')),
(5, _('Five')),
)
country = models.ForeignKey('location.Country', null=True, blank=True,
default=None, on_delete=models.CASCADE,
verbose_name=_('Country'))
toque_number = models.IntegerField(choices=TOQUE_NUMBER_CHOICES)
public_mark_min_value = models.IntegerField()
public_mark_max_value = models.IntegerField()
objects = RatingStrategyManager.from_queryset(RatingStrategyQuerySet)()
class Meta:
"""Meta class."""
verbose_name = _('Rating strategy')
verbose_name_plural = _('Rating strategy')
unique_together = ('country', 'toque_number')
def __str__(self):
return f'{self.country.code if self.country else "Other country"}. ' \
f'"{self.toque_number}": {self.public_mark_min_value}-' \
f'{self.public_mark_max_value}'

View File

@ -149,6 +149,7 @@ class EstablishmentSubTypeBaseSerializer(serializers.ModelSerializer):
'establishment_type': {'write_only': True}
}
class EstablishmentSubTypeGeoSerializer(EstablishmentSubTypeBaseSerializer):
"""Serializer for EstablishmentSuType model w/ index_name."""
@ -223,6 +224,11 @@ class EstablishmentGeoSerializer(EstablishmentBaseSerializer):
]
class RangePriceSerializer(serializers.Serializer):
max = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True, default=0)
min = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True, default=0)
class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
"""Serializer for Establishment model."""
@ -240,6 +246,8 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
menu = MenuSerializers(source='menu_set', many=True, read_only=True)
best_price_menu = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
best_price_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
range_price_menu = RangePriceSerializer(read_only=True)
range_price_carte = RangePriceSerializer(read_only=True)
vintage_year = serializers.ReadOnlyField()
class Meta(EstablishmentBaseSerializer.Meta):
@ -264,6 +272,8 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
'menu',
'best_price_menu',
'best_price_carte',
'range_price_menu',
'range_price_carte',
'transportation',
'vintage_year',
]

View File

@ -1,22 +1,24 @@
from pprint import pprint
import requests
from django.db.models import Q, F
from transfer.models import Establishments, Dishes
from transfer.serializers.establishment import EstablishmentSerializer
from establishment.models import Establishment
from location.models import Address
from transfer.models import Establishments, Dishes
from transfer.serializers.establishment import EstablishmentSerializer
from transfer.serializers.plate import PlateSerializer
def transfer_establishment():
result = []
old_establishments = Establishments.objects.filter(
location__city__name__icontains='paris',
# todo: filter(location__city__name__icontains='paris')
old_establishments = Establishments.objects.exclude(
id__in=list(Establishment.objects.all().values_list('old_id', flat=True))
).exclude(
Q(type='Wineyard') |
Q(location__timezone__isnull=True)
Q(location__timezone__isnull=True),
).prefetch_related(
'establishmentinfos_set',
'schedules_set',
@ -133,6 +135,5 @@ data_types = {
"location_establishment": [
transfer_establishment_addresses
],
"menu": [transfer_menu],
}

View File

@ -7,7 +7,8 @@ from django.dispatch import receiver
from django.utils.translation import gettext_lazy as _
from translation.models import Language
from utils.models import ProjectBaseMixin, SVGImageMixin, TranslatedFieldsMixin, TJSONField
from utils.models import (ProjectBaseMixin, SVGImageMixin, TJSONField,
TranslatedFieldsMixin, get_current_locale)
class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
@ -15,6 +16,13 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
STR_FIELD_NAME = 'name'
TWELVE_HOURS_FORMAT_COUNTRIES = [
'ca', # Canada
'au', # Australia
'us', # USA
'nz', # New Zealand
]
name = TJSONField(null=True, blank=True, default=None,
verbose_name=_('Name'), help_text='{"en-GB":"some text"}')
code = models.CharField(max_length=255, unique=True, verbose_name=_('Code'))
@ -23,6 +31,12 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
languages = models.ManyToManyField(Language, verbose_name=_('Languages'))
old_id = models.IntegerField(null=True, blank=True, default=None)
@property
def time_format(self):
if self.code.lower() not in self.TWELVE_HOURS_FORMAT_COUNTRIES:
return 'HH:mm'
return 'hh:mmA'
@property
def country_id(self):
return self.id
@ -33,6 +47,14 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
verbose_name_plural = _('Countries')
verbose_name = _('Country')
def __str__(self):
str_name = self.code
if isinstance(self.name, dict):
translated_name = self.name.get(get_current_locale())
if translated_name:
str_name = translated_name
return str_name
class Region(models.Model):
"""Region model."""

View File

@ -1,16 +1,20 @@
from django.db.models import Q, QuerySet
from transfer.serializers.location import CountrySerializer, RegionSerializer, CitySerializer, AddressSerializer
from transfer.serializers.location import CountrySerializer, RegionSerializer, \
CitySerializer, AddressSerializer, \
Country
from transfer.models import Cities, Locations
from pprint import pprint
from requests import get
def transfer_countries():
queryset = Cities.objects.raw("""SELECT cities.id, cities.country_code_2
FROM cities WHERE
country_code_2 IS NOT NULL AND
country_code_2 != ""
GROUP BY cities.country_code_2""")
queryset = Cities.objects.raw("""
SELECT cities.id, cities.country_code_2
FROM cities
WHERE country_code_2 IS NOT NULL AND
country_code_2 != ""
GROUP BY cities.id, cities.country_code_2
""")
queryset = [vars(query) for query in queryset]
@ -22,16 +26,24 @@ def transfer_countries():
def transfer_regions():
regions_without_subregion_queryset = Cities.objects.raw("""SELECT cities.id, cities.region_code,
cities.country_code_2, cities.subregion_code
FROM cities WHERE
(subregion_code IS NULL OR
subregion_code = "") AND
region_code IS NOT NULL AND
region_code != "" AND
country_code_2 IS NOT NULL AND
country_code_2 != ""
GROUP BY region_code""")
regions_without_subregion_queryset = Cities.objects.raw("""
SELECT cities.id,
cities.region_code,
cities.country_code_2,
cities.subregion_code
FROM cities
WHERE (subregion_code IS NULL
OR subregion_code = ""
)
AND region_code IS NOT NULL
AND region_code != ""
AND country_code_2 IS NOT NULL
AND country_code_2 != ""
GROUP BY cities.id,
cities.region_code,
cities.country_code_2,
cities.subregion_code
""")
regions_without_subregion_queryset = [vars(query) for query in regions_without_subregion_queryset]
@ -41,25 +53,34 @@ def transfer_regions():
else:
pprint(f"Parent regions serializer errors: {serialized_without_subregion.errors}")
regions_with_subregion_queryset = Cities.objects.raw("""SELECT cities.id, cities.region_code,
cities.country_code_2, cities.subregion_code
FROM cities WHERE
subregion_code IS NOT NULL AND
subregion_code != "" AND
region_code IS NOT NULL AND
region_code != "" AND
country_code_2 IS NOT NULL AND
country_code_2 != ""
AND cities.subregion_code in (
SELECT region_code FROM cities WHERE
(subregion_code IS NULL OR
subregion_code = "") AND
region_code IS NOT NULL AND
region_code != "" AND
country_code_2 IS NOT NULL AND
country_code_2 != ""
)
GROUP BY region_code""")
regions_with_subregion_queryset = Cities.objects.raw("""
SELECT
cities.id,
cities.region_code,
cities.country_code_2,
cities.subregion_code
FROM cities
WHERE subregion_code IS NOT NULL AND
subregion_code != "" AND
region_code IS NOT NULL AND
region_code != "" AND
country_code_2 IS NOT NULL AND
country_code_2 != ""
AND cities.subregion_code in
(
SELECT region_code FROM cities WHERE
(subregion_code IS NULL OR
subregion_code = "") AND
region_code IS NOT NULL AND
region_code != "" AND
country_code_2 IS NOT NULL AND
country_code_2 != ""
)
GROUP BY cities.id,
cities.region_code,
cities.country_code_2,
cities.subregion_code
""")
regions_with_subregion_queryset = [vars(query) for query in regions_with_subregion_queryset]
@ -112,6 +133,17 @@ def transfer_addresses():
pprint(f"Address serializer errors: {serialized_data.errors}")
def update_flags():
queryset = Country.objects.only("id", "code", "svg_image").filter(old_id__isnull=False)
link_to_request = "https://s3.eu-central-1.amazonaws.com/gm-test.com/media"
for query in queryset:
svg_link = f"/svg/country/10-31-2019/{query.code}.svg"
resp = get(f"{link_to_request}{svg_link}")
if resp.status_code == 200:
query.svg_image = svg_link
query.save()
data_types = {
"dictionaries": [
@ -119,5 +151,8 @@ data_types = {
transfer_regions,
transfer_cities,
transfer_addresses
],
"update_country_flag": [
update_flags
]
}

View File

@ -26,8 +26,10 @@ class AwardAdmin(admin.ModelAdmin):
@admin.register(models.Currency)
class CurrencContentAdmin(admin.ModelAdmin):
"""CurrencContent admin"""
class CurrencyContentAdmin(admin.ModelAdmin):
"""Currency Content admin"""
list_display = ['id', 'slug', 'code']
list_display_links = ['slug']
@admin.register(models.Carousel)

View File

@ -0,0 +1,48 @@
# Generated by Django 2.2.4 on 2019-10-31 14:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0023_merge_20191028_0725'),
]
operations = [
migrations.AddField(
model_name='carousel',
name='active',
field=models.BooleanField(default=False, verbose_name='old active'),
),
migrations.AddField(
model_name='carousel',
name='attachment_suffix_url',
field=models.TextField(blank=True, default=None, null=True, verbose_name='old attachment_suffix_url'),
),
migrations.AddField(
model_name='carousel',
name='description',
field=models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='old description'),
),
migrations.AddField(
model_name='carousel',
name='link',
field=models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='old link'),
),
migrations.AddField(
model_name='carousel',
name='link_title',
field=models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='old link_title'),
),
migrations.AddField(
model_name='carousel',
name='old_id',
field=models.PositiveIntegerField(blank=True, default=None, null=True, verbose_name='old id'),
),
migrations.AddField(
model_name='carousel',
name='title',
field=models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='old title'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-10-31 15:30
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0024_auto_20191031_1439'),
]
operations = [
migrations.AddField(
model_name='carousel',
name='is_parse',
field=models.BooleanField(default=False, verbose_name='is parse'),
),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 2.2.4 on 2019-11-01 05:00
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('main', '0025_carousel_is_parse'),
]
operations = [
migrations.AlterField(
model_name='carousel',
name='content_type',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType'),
),
migrations.AlterField(
model_name='carousel',
name='object_id',
field=models.PositiveIntegerField(blank=True, default=None, null=True),
),
]

View File

@ -0,0 +1,20 @@
# Generated by Django 2.2.4 on 2019-11-01 14:23
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('location', '0020_merge_20191030_1714'),
('main', '0026_auto_20191101_0500'),
]
operations = [
migrations.AddField(
model_name='carousel',
name='country',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='location.Country', verbose_name='country'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-03 12:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0027_carousel_country'),
]
operations = [
migrations.AlterField(
model_name='currency',
name='sign',
field=models.CharField(max_length=3, verbose_name='sign'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-03 13:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0028_auto_20191103_1237'),
]
operations = [
migrations.AlterField(
model_name='currency',
name='sign',
field=models.CharField(max_length=5, verbose_name='sign'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-03 13:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0029_auto_20191103_1344'),
]
operations = [
migrations.AlterField(
model_name='currency',
name='sign',
field=models.CharField(max_length=255, verbose_name='sign'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 2.2.4 on 2019-11-03 20:37
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0030_auto_20191103_1350'),
]
operations = [
migrations.AddField(
model_name='currency',
name='code',
field=models.CharField(default=None, max_length=5, null=True, unique=True),
),
migrations.AlterField(
model_name='currency',
name='slug',
field=models.SlugField(max_length=5, unique=True),
),
]

View File

@ -5,6 +5,7 @@ from django.conf import settings
from django.contrib.contenttypes import fields as generic
from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.fields import JSONField
from django.core.validators import EMPTY_VALUES
from django.db import models
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
@ -14,96 +15,8 @@ from configuration.models import TranslationSettings
from location.models import Country
from main import methods
from review.models import Review
from utils.models import (ProjectBaseMixin, TJSONField,
TranslatedFieldsMixin, ImageMixin,
PlatformMixin, URLImageMixin)
from utils.querysets import ContentTypeQuerySetMixin
#
#
# class Tag(models.Model):
# """Tag model."""
# name = models.CharField(max_length=250)
#
#
# class MediaAsset(models.Model):
# """Assets model."""
# PHOTO = 0
# VIDEO = 1
# VIDEO_URL = 2
# PDF = 3
# DOCUMENT = 4
#
# ASSET_TYPE_CHOICES = (
# (PHOTO, _('photo')),
# (VIDEO, _('video')),
# (VIDEO_URL, _('video url')),
# (PDF, _('pdf')),
# (DOCUMENT, _('document'))
# )
#
# AMAZON_S3 = 0
#
# STORAGE_TYPE_CHOICES = (
# (AMAZON_S3, _('amazon s3')),
# )
#
# PUBLIC = 0
# PRIVATE = 1
# ROLE = 2
#
# ACCESS_TYPE_CHOICES = (
# (PUBLIC, _('public')),
# (PRIVATE, _('private')),
# (ROLE, _('role')),
# )
#
# asset_type = models.PositiveSmallIntegerField(
# _('asset type'), choices=ASSET_TYPE_CHOICES, default=PHOTO
# )
# storage_type = models.PositiveSmallIntegerField(
# _('storage type'), choices=STORAGE_TYPE_CHOICES, default=AMAZON_S3
# )
# storage_unit = models.CharField(_('storage unit'), blank=True, default='')
# path = models.CharField(_('path'))
# access_type = models.PositiveSmallIntegerField(
# _('access type'), choices=ACCESS_TYPE_CHOICES, default=PUBLIC)
# asset_text = JSONField(_('asset_text'))
# size = models.IntegerField(_('size'))
# version = models.CharField(_('version'), max_length=250)
# text = JSONField(_('text'))
#
#
# class Contacts(models.Model):
# """Contacts model."""
# address = models.ForeignKey(
# 'location.Address', verbose_name=_('address'), on_delete=models.CASCADE
# )
#
#
# class Social(models.Model):
# """Social model."""
# WEBSITE = 0
# SOCIAL = 1
#
# SOCIAL_TYPE_CHOICES = (
# (WEBSITE, _('website')),
# (SOCIAL, _('social')),
# )
#
# social_type = models.PositiveSmallIntegerField(
# _('social type'), choices=SOCIAL_TYPE_CHOICES
# )
#
#
# class Note(models.Model):
# """Note model."""
#
#
# class Ad(models.Model):
# """Ad model."""
#
from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin,
TranslatedFieldsMixin, PlatformMixin)
class Currency(TranslatedFieldsMixin, models.Model):
@ -111,8 +24,9 @@ class Currency(TranslatedFieldsMixin, models.Model):
name = TJSONField(
_('name'), null=True, blank=True,
default=None, help_text='{"en-GB":"some text"}')
sign = models.CharField(_('sign'), max_length=1)
slug = models.SlugField(max_length=255, unique=True)
sign = models.CharField(_('sign'), max_length=255)
slug = models.SlugField(max_length=5, unique=True)
code = models.CharField(max_length=5, unique=True, null=True, default=None)
class Meta:
verbose_name = _('currency')
@ -130,7 +44,6 @@ class SiteSettingsQuerySet(models.QuerySet):
class SiteSettings(ProjectBaseMixin):
subdomain = models.CharField(max_length=255, db_index=True, unique=True,
verbose_name=_('Subdomain'))
country = models.OneToOneField(Country, on_delete=models.PROTECT,
@ -279,13 +192,41 @@ class AwardType(models.Model):
class CarouselQuerySet(models.QuerySet):
"""Carousel QuerySet."""
def is_parsed(self):
"""Parsed carousel objects."""
return self.filter(is_parse=True)
def active(self):
"""Active carousel objects."""
return self.filter(active=True)
def by_country_code(self, code):
"""Filter collection by country code."""
return self.filter(country__code=code)
class Carousel(models.Model):
"""Carousel model."""
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, blank=True, null=True, default=None)
object_id = models.PositiveIntegerField(blank=True, null=True, default=None)
content_object = generic.GenericForeignKey('content_type', 'object_id')
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
title = models.CharField(_('old title'), max_length=255, blank=True, null=True, default=None)
link = models.CharField(_('old link'), max_length=255, blank=True, null=True, default=None)
attachment_suffix_url = models.TextField(_('old attachment_suffix_url'), blank=True, null=True, default=None)
description = models.CharField(_('old description'), max_length=255, blank=True, null=True, default=None)
link_title = models.CharField(_('old link_title'), max_length=255, blank=True, null=True, default=None)
country = models.ForeignKey(
Country,
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name=_('country')
)
active = models.BooleanField(_('old active'), default=False)
is_parse = models.BooleanField(_('is parse'), default=False)
objects = CarouselQuerySet.as_manager()
class Meta:
@ -325,6 +266,8 @@ class Carousel(models.Model):
@property
def image_url(self):
if self.attachment_suffix_url:
return f'https://s3.eu-central-1.amazonaws.com/gm-test.com/media/{self.attachment_suffix_url}'
if hasattr(self.content_object, 'image_url'):
return self.content_object.image_url
@ -340,5 +283,12 @@ class Carousel(models.Model):
@property
def model_name(self):
if hasattr(self.content_object, 'establishment_type'):
return self.content_object.establishment_type.name_translated
from establishment.models import Establishment
from news.models import News
if isinstance(self.content_object, Establishment):
return self.content_object.establishment_type.index_name
elif isinstance(self.content_object, News):
return self.content_type.model
elif self.link not in EMPTY_VALUES:
return 'external'
return None

View File

@ -64,6 +64,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
country_code = serializers.CharField(source='subdomain', read_only=True)
country_name = serializers.CharField(source='country.name_translated', read_only=True)
time_format = serializers.CharField(source='country.time_format', read_only=True)
class Meta:
"""Meta class."""
@ -71,6 +72,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
model = models.SiteSettings
fields = (
'country_code',
'time_format',
'subdomain',
'pinterest_page_url',
'twitter_page_url',
@ -81,7 +83,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
'ad_config',
'published_features',
'currency',
'country_name'
'country_name',
)
@ -135,6 +137,7 @@ class AwardSerializer(AwardBaseSerializer):
class CarouselListSerializer(serializers.ModelSerializer):
"""Serializer for retrieving list of carousel items."""
model_name = serializers.CharField()
name = serializers.CharField()
toque_number = serializers.IntegerField()
@ -158,6 +161,7 @@ class CarouselListSerializer(serializers.ModelSerializer):
'vintage_year',
'last_award',
'slug',
'link',
]

View File

@ -71,7 +71,8 @@ card = {
"facebook_page_url": "facebook_page_url",
"instagram_page_url": "instagram_page_url",
"contact_email": "contact_email",
"config": ("config", "django.db.models.JSONField") #TODO в качесте ключа использовать country_code_2 из legacy - ?
"config": ("config", "django.db.models.JSONField")
# TODO в качесте ключа использовать country_code_2 из legacy - ?
},
# "relations": {
# # Как работать c отношение OneToOneField
@ -133,7 +134,7 @@ card = {
"vintage_year": "year",
}
},
#TODO вопрос с content_type
# TODO вопрос с content_type
"relations": {
"AwardTypes": [(
("award_type", None),
@ -143,4 +144,4 @@ card = {
}
}
used_apps = ("locations", )
used_apps = ("locations",)

View File

@ -0,0 +1,23 @@
from pprint import pprint
from django.db.models import F
from transfer.models import CarouselElements
from transfer.serializers.carousel import CarouselSerializer
def transfer_carousel():
queryset = CarouselElements.objects.all().annotate(
country=F('home_page__site__country_code_2'),
)
serialized_data = CarouselSerializer(data=list(queryset.values()), many=True)
if serialized_data.is_valid():
serialized_data.save()
else:
pprint(f'Carousel serializer errors: {serialized_data.errors}')
data_types = {
'whirligig': [transfer_carousel]
}

View File

@ -8,5 +8,5 @@ common_urlpatterns = [
path('awards/', AwardView.as_view(), name='awards_list'),
path('awards/<int:pk>/', AwardRetrieveView.as_view(), name='awards_retrieve'),
path('carousel/', CarouselListView.as_view(), name='carousel-list'),
path('determine-location/', DetermineLocation.as_view(), name='determine-location')
path('determine-location/', DetermineLocation.as_view(), name='determine-location')
]

View File

@ -61,11 +61,19 @@ class AwardRetrieveView(generics.RetrieveAPIView):
class CarouselListView(generics.ListAPIView):
"""Return list of carousel items."""
queryset = models.Carousel.objects.all()
queryset = models.Carousel.objects.is_parsed().active()
serializer_class = serializers.CarouselListSerializer
permission_classes = (permissions.AllowAny,)
pagination_class = None
def get_queryset(self):
country_code = self.request.country_code
qs = models.Carousel.objects.is_parsed().active()
if country_code:
qs = qs.by_country_code(country_code)
return qs
class DetermineLocation(generics.GenericAPIView):
"""Determine user's location."""

View File

@ -0,0 +1,35 @@
from django.core.management.base import BaseCommand
from news.models import News, NewsType
from tag.models import Tag, TagCategory
from transfer.models import PageMetadata, Pages, PageTexts
class Command(BaseCommand):
help = 'Remove old news from new bd'
def handle(self, *args, **kwargs):
count = 0
news_type, _ = NewsType.objects.get_or_create(name='News')
tag_cat, _ = TagCategory.objects.get_or_create(index_name='category')
news_type.tag_categories.add(tag_cat)
news_type.save()
old_news_tag = PageMetadata.objects.filter(key='category', page__pagetexts__isnull=False)
for old_tag in old_news_tag:
old_id_list = old_tag.page.pagetexts_set.all().values_list('id', flat=True)
# Make Tag
new_tag, created = Tag.objects.get_or_create(category=tag_cat, value=old_tag.value)
if created:
new_tag.label = {'en-GB': new_tag.value}
new_tag.save()
for id in old_id_list:
if isinstance(id, int):
news = News.objects.filter(old_id=id).first()
if news:
news.tags.add(new_tag)
news.save()
count += 1
self.stdout.write(self.style.WARNING(f'Create or update {count} objects.'))

View File

@ -7,6 +7,7 @@ from rest_framework.reverse import reverse
from rating.models import Rating
from utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin, ProjectBaseMixin
from utils.querysets import TranslationQuerysetMixin
class NewsType(models.Model):
@ -27,7 +28,7 @@ class NewsType(models.Model):
return self.name
class NewsQuerySet(models.QuerySet):
class NewsQuerySet(TranslationQuerysetMixin):
"""QuerySet for model News"""
def rating_value(self):

View File

@ -215,7 +215,7 @@ class NewsDetailWebSerializer(NewsDetailSerializer):
'same_theme',
'should_read',
'agenda',
'banner'
'banner',
)

View File

@ -21,8 +21,9 @@ class NewsMixinView:
from django.conf import settings
"""Override get_queryset method."""
qs = models.News.objects.published().with_base_related() \
.order_by('-is_highlighted', '-created')
qs = models.News.objects.published() \
.with_base_related() \
.order_by('-is_highlighted', '-created')
country_code = self.request.country_code
if country_code:
@ -36,7 +37,7 @@ class NewsMixinView:
qs = qs.by_country_code(country_code)
else:
qs = models.News.objects.filter(
id__in=settings.HARDCODED_INTERNATIONAL_NEWS_IDS)
old_id__in=settings.HARDCODED_INTERNATIONAL_NEWS_IDS)
return qs
# temp code

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-01 09:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('partner', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='partner',
name='image',
field=models.URLField(null=True, verbose_name='Partner image URL'),
),
]

View File

@ -4,9 +4,10 @@ from django.utils.translation import gettext_lazy as _
from utils.models import ImageMixin, ProjectBaseMixin
class Partner(ProjectBaseMixin, ImageMixin):
class Partner(ProjectBaseMixin):
"""Partner model."""
url = models.URLField(verbose_name=_('Partner URL'))
image = models.URLField(verbose_name=_('Partner image URL'), null=True)
class Meta:
verbose_name = _('partner')

View File

@ -7,6 +7,8 @@ from transfer.serializers.partner import PartnerSerializer
def transfer_partner():
queryset = EstablishmentBacklinks.objects.filter(type="Partner")
# queryset = EstablishmentBacklinks.objects.all() # Partner and Sponsor
serialized_data = PartnerSerializer(data=list(queryset.values()), many=True)
if serialized_data.is_valid():
serialized_data.save()

View File

@ -0,0 +1,29 @@
# Generated by Django 2.2.4 on 2019-10-30 13:15
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('product', '0002_product_slug'),
]
operations = [
migrations.AddField(
model_name='product',
name='old_id',
field=models.IntegerField(blank=True, null=True, verbose_name='Product old id'),
),
migrations.AddField(
model_name='product',
name='old_id_establishment',
field=models.IntegerField(blank=True, null=True, verbose_name='Establishment old id'),
),
migrations.AlterField(
model_name='product',
name='establishment',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='establishment.Establishment', verbose_name='establishment'),
),
]

View File

@ -0,0 +1,33 @@
# Generated by Django 2.2.4 on 2019-10-31 09:23
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('product', '0003_auto_20191030_1315'),
]
operations = [
migrations.RemoveField(
model_name='product',
name='old_id_establishment',
),
migrations.AlterField(
model_name='product',
name='establishment',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='products', to='establishment.Establishment', verbose_name='establishment'),
),
migrations.AlterField(
model_name='product',
name='old_id',
field=models.IntegerField(blank=True, null=True),
),
migrations.AlterField(
model_name='productsubtype',
name='index_name',
field=models.CharField(choices=[('rum', 'Rum'), ('other', 'Other'), ('extra brut', 'extra brut'), ('brut', 'brut'), ('brut nature', 'brut nature'), ('demi-sec', 'demi-sec'), ('Extra Dry', 'Extra Dry'), ('dosage zero', 'dosage zero'), ('sec', 'sec'), ('doux', 'doux'), ('moelleux', 'moelleux')], db_index=True, max_length=50, unique=True, verbose_name='Index name'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 2.2.4 on 2019-10-31 09:29
import django.contrib.postgres.fields.jsonb
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('product', '0004_auto_20191031_0923'),
]
operations = [
migrations.AlterField(
model_name='product',
name='characteristics',
field=django.contrib.postgres.fields.jsonb.JSONField(null=True, verbose_name='Characteristics'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 2.2.4 on 2019-10-31 09:30
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('product', '0005_auto_20191031_0929'),
]
operations = [
migrations.AlterField(
model_name='product',
name='establishment',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='establishment.Establishment', verbose_name='establishment'),
),
]

View File

@ -0,0 +1,29 @@
# Generated by Django 2.2.4 on 2019-10-31 14:08
import django.contrib.postgres.fields.jsonb
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('product', '0006_auto_20191031_0930'),
]
operations = [
migrations.RemoveField(
model_name='product',
name='old_id',
),
migrations.AlterField(
model_name='product',
name='characteristics',
field=django.contrib.postgres.fields.jsonb.JSONField(verbose_name='Characteristics', null=True),
),
migrations.AlterField(
model_name='product',
name='establishment',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='products', to='establishment.Establishment', verbose_name='establishment'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 2.2.4 on 2019-10-31 14:10
import django.contrib.postgres.fields.jsonb
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('product', '0007_auto_20191031_1408'),
]
operations = [
migrations.AlterField(
model_name='product',
name='characteristics',
field=django.contrib.postgres.fields.jsonb.JSONField(null=True, verbose_name='Characteristics'),
),
]

View File

@ -71,8 +71,10 @@ class EstablishmentDocumentViewSet(BaseDocumentViewSet):
]
search_fields = {
'name': {'fuzziness': 'auto:3,4'},
'name_translated': {'fuzziness': 'auto:3,4'},
'name': {'fuzziness': 'auto:3,4',
'boost': '2'},
'name_translated': {'fuzziness': 'auto:3,4',
'boost': '2'},
'description': {'fuzziness': 'auto'},
}
translated_search_fields = (

View File

@ -5,8 +5,13 @@ from .models import Tag, TagCategory
@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
"""Admin model for model Tag."""
list_display = ['id', 'value', 'category']
list_display_links = ['id', 'value',]
list_filter = ['value']
@admin.register(TagCategory)
class TagCategoryAdmin(admin.ModelAdmin):
"""Admin model for model TagCategory."""
list_display = ['id', 'index_name', ]
list_display_links = ['id', 'index_name', ]

View File

@ -1,11 +1,10 @@
"""Tag app filters."""
from django_filters import rest_framework as filters
from establishment.models import EstablishmentType
from django.conf import settings
from tag import models
class TagCategoryFilterSet(filters.FilterSet):
"""TagCategory filterset."""
class TagsBaseFilterSet(filters.FilterSet):
# Object type choices
NEWS = 'news'
@ -19,6 +18,18 @@ class TagCategoryFilterSet(filters.FilterSet):
type = filters.MultipleChoiceFilter(choices=TYPE_CHOICES,
method='filter_by_type')
def filter_by_type(self, queryset, name, value):
if self.NEWS in value:
queryset = queryset.for_news()
if self.ESTABLISHMENT in value:
queryset = queryset.for_establishments()
return queryset
class TagCategoryFilterSet(TagsBaseFilterSet):
"""TagCategory filterset."""
establishment_type = filters.ChoiceFilter(
choices=EstablishmentType.INDEX_NAME_TYPES,
method='by_establishment_type')
@ -30,13 +41,31 @@ class TagCategoryFilterSet(filters.FilterSet):
fields = ('type',
'establishment_type', )
def filter_by_type(self, queryset, name, value):
if self.NEWS in value:
queryset = queryset.for_news()
if self.ESTABLISHMENT in value:
queryset = queryset.for_establishments()
return queryset
# todo: filter by establishment type
def by_establishment_type(self, queryset, name, value):
return queryset.by_establishment_type(value)
class TagsFilterSet(TagsBaseFilterSet):
"""Chosen tags filterset."""
class Meta:
"""Meta class."""
model = models.Tag
fields = ('type',)
# TMP TODO remove it later
# Временный хардкод для демонстрации 4 ноября, потом удалить!
def filter_by_type(self, queryset, name, value):
""" Overrides base filter. Temporary decision"""
if not (settings.NEWS_CHOSEN_TAGS and settings.ESTABLISHMENT_CHOSEN_TAGS):
return super().filter_by_type(queryset, name, value)
queryset = models.Tag.objects
if self.NEWS in value:
queryset = queryset.for_news().filter(value__in=settings.NEWS_CHOSEN_TAGS).distinct('value')
if self.ESTABLISHMENT in value:
queryset = queryset.for_establishments().filter(value__in=settings.ESTABLISHMENT_CHOSEN_TAGS).distinct(
'value')
return queryset

View File

@ -10,7 +10,9 @@ class Command(BaseCommand):
def handle(self, *args, **kwargs):
existing_establishment = Establishment.objects.filter(old_id__isnull=False)
existing_establishment = Establishment.objects.filter(
old_id__isnull=False, tags__isnull=True
)
ESTABLISHMENT = 1
SHOP = 2
RESTAURANT = 3
@ -52,18 +54,35 @@ class Command(BaseCommand):
# create Tag
for tag in key_value.metadata_set.filter(
establishment__id__in=list(existing_establishment.values_list('old_id', flat=True))):
establishment__id__in=list(
existing_establishment.values_list('old_id', flat=True)
)):
new_tag, _ = Tag.objects.get_or_create(
label={
'en-GB': tag.value,
'fr-FR': tag.value,
'ru-RU': tag.value,
},
new_tag, created = Tag.objects.get_or_create(
value=tag.value,
category=tag_category,
)
est = existing_establishment.get(old_id=tag.establishment_id)
est.tags.add(new_tag)
est.save()
if created:
sp = tag.value.split('_')
value = ' '.join([sp[0].capitalize()] + sp[1:])
trans = {
'en-GB': value,
'fr-FR': value,
'ru-RU': value,
}
aliases = legacy.MetadatumAliases.objects.filter(value=tag.value)
for alias in aliases:
trans[alias.locale] = alias.meta_alias
new_tag.label = trans
new_tag.save()
est = existing_establishment.filter(
old_id=tag.establishment_id).first()
if est:
est.tags.add(new_tag)
est.save()

View File

@ -0,0 +1,30 @@
from django.core.management.base import BaseCommand
from establishment.models import Establishment, EstablishmentType
from transfer import models as legacy
from tag.models import Tag, TagCategory
class Command(BaseCommand):
help = 'Add tags translation from old db to new db'
def handle(self, *args, **kwargs):
translation = legacy.MetadatumAliases.objects.all()
# Humanisation for default values
tags = Tag.objects.all()
for tag in tags:
value = tag.label
for k, v in value.items():
sp = v.split('_')
v = ' '.join([sp[0].capitalize()] + sp[1:])
tag.label[k] = v
tag.save()
for trans in translation:
tag = Tag.objects.filter(value=trans.value).first()
if tag:
tag.label.update(
{trans.locale: trans.meta_alias}
)
tag.save()

View File

@ -0,0 +1,37 @@
# Generated by Django 2.2.4 on 2019-11-01 12:44
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('location', '0020_merge_20191030_1714'),
('tag', '0007_auto_20191030_1514'),
]
operations = [
migrations.RemoveField(
model_name='tag',
name='priority',
),
migrations.CreateModel(
name='ChosenTagSettings',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('priority', models.IntegerField(default=0)),
('country', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='location.Country')),
('tag', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tag.Tag')),
],
options={
'verbose_name': 'Tag',
'verbose_name_plural': 'Tags',
},
),
migrations.AddField(
model_name='tag',
name='chosen_tag_settings',
field=models.ManyToManyField(through='tag.ChosenTagSettings', to='location.Country'),
),
]

View File

@ -1,16 +1,26 @@
"""Tag app models."""
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.translation import gettext_lazy as _
from configuration.models import TranslationSettings
from location.models import Country
from utils.models import TJSONField, TranslatedFieldsMixin
class TagQuerySet(models.QuerySet):
def filter_chosen(self):
return self.exclude(priority__isnull=True)
def for_news(self):
"""Select chosen tags for news."""
return self.filter(category__news_types__isnull=False)
def for_establishments(self):
"""Select chosen tags for establishments."""
return self.filter(models.Q(category__establishment_types__isnull=False) |
models.Q(category__establishment_subtypes__isnull=False))
def order_by_priority(self):
return self.order_by('priority')
return self.order_by('chosentagsettings__priority')
class Tag(TranslatedFieldsMixin, models.Model):
@ -24,7 +34,8 @@ class Tag(TranslatedFieldsMixin, models.Model):
category = models.ForeignKey('TagCategory', on_delete=models.CASCADE,
null=True, related_name='tags',
verbose_name=_('Category'))
priority = models.IntegerField(unique=True, null=True, default=None)
chosen_tag_settings = models.ManyToManyField(Country, through='ChosenTagSettings')
objects = TagQuerySet.as_manager()
@ -35,11 +46,29 @@ class Tag(TranslatedFieldsMixin, models.Model):
verbose_name_plural = _('Tags')
def __str__(self):
label = 'None'
lang = TranslationSettings.get_solo().default_language
if self.label and lang in self.label:
label = self.label[lang]
return f'id:{self.id}-{label}'
return f'Tag (id = {self.id}, label_translated = {self.label_translated})'
class ChosenTagSettingsQuerySet(models.QuerySet):
def by_country_code(self, country_code):
return self.filter(country__code=country_code)
class ChosenTagSettings(models.Model):
"""Tag model."""
tag = models.ForeignKey(Tag, on_delete=models.PROTECT)
country = models.ForeignKey(Country, on_delete=models.PROTECT)
priority = models.IntegerField(null=False, default=0)
objects = ChosenTagSettingsQuerySet.as_manager()
class Meta:
"""Meta class."""
verbose_name = _('Tag')
verbose_name_plural = _('Tags')
class TagCategoryQuerySet(models.QuerySet):
@ -55,7 +84,7 @@ class TagCategoryQuerySet(models.QuerySet):
def for_news(self):
"""Select tag categories for news."""
return self.filter(news_types__isnull=True)
return self.filter(news_types__isnull=False)
def for_establishments(self):
"""Select tag categories for establishments."""
@ -106,8 +135,4 @@ class TagCategory(TranslatedFieldsMixin, models.Model):
verbose_name_plural = _('Tag categories')
def __str__(self):
label = 'None'
lang = TranslationSettings.get_solo().default_language
if self.label and lang in self.label:
label = self.label[lang]
return f'id:{self.id}-{label}'
return self.index_name

View File

@ -12,9 +12,9 @@ from utils.serializers import TranslatedField
class TagBaseSerializer(serializers.ModelSerializer):
"""Serializer for model Tag."""
# todo: refactor this
# label_translated = TranslatedField()
label_translated = serializers.CharField(source='value', read_only=True, allow_null=True)
label_translated = TranslatedField()
# label_translated = serializers.CharField(source='value', read_only=True, allow_null=True)
index_name = serializers.CharField(source='value', read_only=True, allow_null=True)
class Meta:
"""Meta class."""
@ -23,6 +23,7 @@ class TagBaseSerializer(serializers.ModelSerializer):
fields = (
'id',
'label_translated',
'index_name',
)

View File

@ -7,7 +7,7 @@ app_name = 'tag'
router = SimpleRouter()
router.register(r'categories', views.TagCategoryViewSet)
router.register(r'chosen_tags', views.ChosenTagsView, basename='Tag')
router.register(r'chosen_tags', views.ChosenTagsView)
urlpatterns = [

View File

@ -1,21 +1,45 @@
"""Tag views."""
from django.conf import settings
from rest_framework import permissions
from rest_framework import viewsets, mixins, status, generics
from rest_framework.decorators import action
from rest_framework.response import Response
from tag import filters, models, serializers
from rest_framework import permissions
class ChosenTagsView(generics.ListAPIView, viewsets.GenericViewSet):
pagination_class = None
permission_classes = (permissions.AllowAny,)
serializer_class = serializers.TagBaseSerializer
filterset_class = filters.TagsFilterSet
queryset = models.Tag.objects.all()
def get_queryset(self):
return models.Tag.objects\
.filter_chosen() \
result_tags_ids = models.ChosenTagSettings.objects \
.by_country_code(self.request.country_code) \
.values('tag_id')
return models.Tag.objects \
.filter(id__in=result_tags_ids) \
.order_by_priority()
def list(self, request, *args, **kwargs):
# TMP TODO remove it later
# Временный хардкод для демонстрации 4 ноября, потом удалить!
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
result_list = serializer.data
if request.query_params.get('type') and (settings.ESTABLISHMENT_CHOSEN_TAGS or settings.NEWS_CHOSEN_TAGS):
ordered_list = settings.ESTABLISHMENT_CHOSEN_TAGS if request.query_params.get('type') == 'establishment' else settings.NEWS_CHOSEN_TAGS
result_list = sorted(result_list, key=lambda x: ordered_list.index(x['index_name']))
return Response(result_list)
# User`s views & viewsets
class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
@ -23,8 +47,8 @@ class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
filterset_class = filters.TagCategoryFilterSet
pagination_class = None
permission_classes = (permissions.AllowAny, )
queryset = models.TagCategory.objects.with_tags().with_base_related().\
permission_classes = (permissions.AllowAny,)
queryset = models.TagCategory.objects.with_tags().with_base_related(). \
distinct()
serializer_class = serializers.TagCategoryBaseSerializer
@ -62,7 +86,7 @@ class TagBackOfficeViewSet(mixins.ListModelMixin, mixins.CreateModelMixin,
"""List/create tag view."""
pagination_class = None
permission_classes = (permissions.IsAuthenticated, )
permission_classes = (permissions.IsAuthenticated,)
queryset = models.Tag.objects.all()
serializer_class = serializers.TagBackOfficeSerializer
bind_object_serializer_class = serializers.TagBindObjectSerializer
@ -96,7 +120,7 @@ class TagCategoryBackOfficeViewSet(mixins.CreateModelMixin,
TagCategoryViewSet):
"""ViewSet for TagCategory model for BackOffice users."""
permission_classes = (permissions.IsAuthenticated, )
permission_classes = (permissions.IsAuthenticated,)
queryset = TagCategoryViewSet.queryset.with_extended_related()
serializer_class = serializers.TagCategoryBackOfficeDetailSerializer
bind_object_serializer_class = serializers.TagCategoryBindObjectSerializer

View File

@ -8,7 +8,7 @@ class Command(BaseCommand):
"""Типы данных для трансфера
ВНИМАНИЕ: первые буквы типов данных должны быть уникальны!
"""
DATA_TYPES = [
SHORT_DATA_TYPES = [
'dictionaries',
'news',
'account',
@ -22,20 +22,39 @@ class Command(BaseCommand):
'tmp',
'menu',
'location_establishment',
'wine_color',
'whirligig',
]
LONG_DATA_TYPES = [
'update_country_flag',
]
def handle(self, *args, **options):
"""Находим включённую опцию путём пересечения множества типов данных и множества включённых опций"""
data_type = list(set(option for option in options.keys() if options[option]) & set(self.DATA_TYPES))
data_type = list(set(option for option in options.keys() if options[option]) & set(self.LONG_DATA_TYPES))
if len(data_type) != 1:
print("You must set correct option!\r\nYou can get options list with \r\n\r\n\tmanage.py help transfer\r\n")
exit(1)
transfer_objects(data_type[0])
data_type = list(set(option for option in options.keys() if options[option]) & set(self.SHORT_DATA_TYPES))
if len(data_type) != 1:
print("You must set correct option!\r\nYou can get options list with \r\n\r\n\tmanage.py help transfer\r\n")
exit(1)
else:
data_type = data_type[0]
else:
data_type = data_type[0]
transfer_objects(data_type)
def add_arguments(self, parser):
for option_type in self.LONG_DATA_TYPES:
parser.add_argument(
f'--{option_type}',
action='store_true',
default=False,
help=f'Transfer {option_type} objects'
)
"""Добавляем опции к команде, основываясь на типах данных, определённых в DATA_TYPES"""
for option_type in self.DATA_TYPES:
for option_type in self.SHORT_DATA_TYPES:
parser.add_argument(
f'-{option_type[:1]}',
f'--{option_type}',

View File

@ -553,6 +553,7 @@ class EstablishmentInfos(MigrateMixin):
website = models.CharField(max_length=255, blank=True, null=True)
facebook = models.CharField(max_length=255, blank=True, null=True)
twitter = models.CharField(max_length=255, blank=True, null=True)
instagram = models.TextField(blank=True, null=True)
lafourchette = models.CharField(max_length=255, blank=True, null=True)
pub = models.IntegerField(blank=True, null=True)
created_at = models.DateTimeField()
@ -967,3 +968,51 @@ class WineTypes(MigrateMixin):
# class Meta:
# managed = False
# db_table = 'products'
class HomePages(models.Model):
using = 'legacy'
site = models.ForeignKey(Sites, models.DO_NOTHING, blank=True, null=True)
selection_of_week = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'home_pages'
class CarouselElements(MigrateMixin):
using = 'legacy'
title = models.CharField(max_length=255, blank=True, null=True)
link = models.CharField(max_length=255, blank=True, null=True)
home_page = models.ForeignKey(HomePages, models.DO_NOTHING, blank=True, null=True)
created_at = models.DateTimeField()
updated_at = models.DateTimeField()
attachment_file_name = models.CharField(max_length=255, blank=True, null=True)
attachment_content_type = models.CharField(max_length=255, blank=True, null=True)
attachment_file_size = models.IntegerField(blank=True, null=True)
attachment_updated_at = models.DateTimeField(blank=True, null=True)
attachment_suffix_url = models.TextField(blank=True, null=True)
geometries = models.CharField(max_length=1024, blank=True, null=True)
active = models.IntegerField(blank=True, null=True)
description = models.CharField(max_length=255, blank=True, null=True)
link_title = models.CharField(max_length=255, blank=True, null=True)
class Meta:
managed = False
db_table = 'carousel_elements'
class MetadatumAliases(MigrateMixin):
"""MetadatumAliases model."""
using = 'legacy'
meta_alias = models.CharField(max_length=255, blank=True, null=True)
value = models.CharField(max_length=255, blank=True, null=True)
locale = models.CharField(max_length=255, blank=True, null=True)
created_at = models.DateTimeField()
updated_at = models.DateTimeField()
class Meta:
managed = False
db_table = 'metadatum_aliases'

View File

@ -0,0 +1,68 @@
from django.contrib.contenttypes.models import ContentType
from rest_framework import serializers
from establishment.models import Establishment
from location.models import Country
from main.models import Carousel
from news.models import News
def get_obj_data(model, slug):
try:
obj = model.objects.get(slug=slug)
except model.DoesNotExist:
return None, None
else:
content_type = ContentType.objects.get_for_model(obj)
return obj.id, content_type.id
class CarouselSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField(allow_null=True, allow_blank=True)
link = serializers.CharField(allow_null=True)
link_title = serializers.CharField(allow_null=True, allow_blank=True)
description = serializers.CharField(allow_null=True, allow_blank=True)
attachment_suffix_url = serializers.CharField(allow_null=True)
active = serializers.IntegerField()
country = serializers.CharField(allow_null=True)
def create(self, validated_data):
object_id, content_type_id = self.get_content_type(validated_data)
validated_data.update({
'old_id': validated_data['id'],
'country': self.get_country(validated_data),
'active': bool(int(validated_data['active'])),
'content_type_id': content_type_id,
'object_id': object_id,
'is_parse': bool(object_id),
})
validated_data.pop('id')
obj, _ = Carousel.objects.update_or_create(**validated_data)
return obj
@staticmethod
def get_country(data):
return Country.objects.filter(code__iexact=data['country']).first()
@staticmethod
def get_content_type(data):
link = data['link']
if not link:
return None
obj_data = None, None
site = 'gaultmillau.com'
if site in link:
data = link.split('/')
try:
_type = data[3]
except IndexError:
pass
else:
if _type in ('news', 'pages'):
obj_data = get_obj_data(News, data[4])
elif _type == 'restaurant':
obj_data = get_obj_data(Establishment, data[4])
return obj_data

View File

@ -95,7 +95,6 @@ class EstablishmentSerializer(serializers.ModelSerializer):
if address:
return address.id
return None
# return None
@staticmethod
def get_type(data):

View File

@ -71,7 +71,7 @@ class RegionSerializer(serializers.ModelSerializer):
print(data)
if "subregion_code" in data and data["subregion_code"] is not None and data["subregion_code"].strip() != "":
try:
parent_region = Region.objects.get(code=str(data['region_code']))
parent_region = Region.objects.filter(code=str(data['region_code'])).first()
except Exception as e:
raise ValueError(f"Parent region error with {data}: {e}")

View File

@ -4,12 +4,80 @@ from partner.models import Partner
class PartnerSerializer(serializers.ModelSerializer):
backlink_url = serializers.CharField(source="url")
partnership_icon = serializers.CharField()
partnership_name = serializers.CharField()
class Meta:
model = Partner
fields = (
"backlink_url",
"partnership_icon",
"partnership_name"
)
def validate(self, data):
data["image"] = partnership_to_image_url.get(data["partnership_name"]).get(data["partnership_icon"])
data.pop("partnership_name")
data.pop("partnership_icon")
return data
def create(self, validated_data):
return Partner.objects.create(**validated_data)
partnership_to_image_url = {
# partnership_name
"tables-auberges": {
# partnership_icon
"Table Gastronomique":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/tables-auberges/Table Gastronomique-c1908231742bc0d0909c03cdac723c1daa3ee620134e8a6fbfae78efdaab8263.png",
"Bistrot Gourmand":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/tables-auberges/Bistrot Gourmand-fdf0527d8ed05d9c7d26456e531301325582f04e1f8e5d4c283ee4eac367dba1.png",
"Auberges de Village":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/tables-auberges/Auberges de Village-39aab1bbc678a6a5f7e0a2c9b8565bb6d21b01294371533580cdff0d9aa80da0.png",
"Table de Prestige":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/tables-auberges/Table de Prestige-6bf4ab0fcc56d89ffc97cc71553f0b1d21b92f4b5ef7656b832ab03e5c6ff31c.png",
"Table de Terroir":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/tables-auberges/Table de Terroir-e72a35a60c4a4575c162398d7355fc77787f368ff240ff8725dc24a37a497be7.png"
},
"riedel": {
"riedel":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/riedel/riedel-1fe0fa8298ae76d0a2de6e00316d2dd4357cace659cc0398629ae4c117bd114e.png"
},
"lavazza": {
"lavazza":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/lavazza/lavazza-9a013b9f954dd63ba871019a1fcd55ea5cb84b38ab2dbff47ee9464f671195bb.png"
},
"kaviari": {
"Kaviari Paris":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/kaviari/Kaviari Paris-e6c4fe81a1d5257854f9b8e28cb244b01a9129ed01056cb98e809f70ec7b5fcf.png"
},
"mutti": {
"mutti":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/mutti/mutti-86f8514b03e096b8e6843e8885756d311486c461a5b8c4f2f10f75995b146814.png"
},
"nespresso": {
"nespresso":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/nespresso/nespresso-c401e553731c68a364754fe512f25889398d42f98bf8edbe1233695b546d1c5d.png"
},
"le-manoir": {
"le-manoir":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/le-manoir/le-manoir-d6a616bebca2948c147ed7c58d9883682ee2d4a3779dea98e9d1a94f17e14771.png"
},
"discovery-cheque": {
"discovery-cheque":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/discovery-cheque/discovery-cheque-665a3c60d3d6302897863b90245f405979760a27bea06c98aa4130b2c61276fb.png"
},
"mineralwater-selters": {
"Mineral Water Selters":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/mineralwater-selters/Mineral Water Selters-2bac82327955c4357b51feff50bd6a2466705f85cb8e59875cb0192a161fd1d4.png"
},
"mineral-water-acquamorelli": {
"Mineral Water Acqua Morelli":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/mineral-water-acquamorelli/Mineral Water Acqua Morelli-4032ba6b4da7f79dcf005809423fc663cfb49199d6ce95f3cfe99a7705359ac4.png"
},
"mastercard-maestro": {
"MastercardMaestro":
"https://1dc3f33f6d.optimicdn.com/assets/establishment-backlinks/mastercard-maestro/MastercardMaestro-718680bc48d98c4a7417a14a62e4ba2d3af980361256739d980e7b453552b5d8.png"
}
}

View File

@ -8,7 +8,9 @@ def transfer_objects(data_type):
for app in apps.get_app_configs():
if exists(f"{app.path}/transfer_data.py"):
card_module = SourceFileLoader("transfer", f"{app.path}/transfer_data.py").load_module()
if not hasattr(card_module, "data_types") or not isinstance(card_module.data_types, dict) or len(card_module.data_types) < 1:
if not hasattr(card_module, "data_types") \
or not isinstance(card_module.data_types, dict) \
or len(card_module.data_types) < 1:
continue
for module_data_type, transfer_funcs in card_module.data_types.items():

View File

@ -11,7 +11,6 @@ from django.http.request import HttpRequest
from django.utils.timezone import datetime
from rest_framework import status
from rest_framework.request import Request
from os.path import exists
logger = logging.getLogger(__name__)
@ -64,7 +63,7 @@ def image_path(instance, filename):
def svg_image_path(instance, filename):
"""Determine SVG path method."""
filename = '%s.svg' % generate_code()
return 'image/svg/%s/%s/%s' % (
return 'svg/%s/%s/%s' % (
instance._meta.model_name,
datetime.now().strftime(settings.REST_DATE_FORMAT),
filename)

View File

@ -78,6 +78,8 @@ def translate_field(self, field_name):
# fallback
if value is None:
value = field.get(get_default_locale())
if value is None:
value = field.get(next(iter(field.keys()), None))
return value
return None
return translate

View File

@ -6,6 +6,7 @@ from django.db import models
from django.db.models import Q, F
from utils.methods import get_contenttype
from utils.models import TJSONField
class ContentTypeQuerySetMixin(models.QuerySet):
@ -56,3 +57,24 @@ class RelatedObjectsCountMixin(models.QuerySet):
return self._annotate_related_objects_count()\
.annotate(all_related_count=exp)\
.filter(all_related_count__gt=count)
class TranslationQuerysetMixin(models.QuerySet):
def _get_translatable_fields(self):
"""Get translatable fields from model."""
translatable_fields = []
model = self.model
for field in model._meta.fields:
field_name = field.name
if isinstance(field, TJSONField):
translatable_fields.append(field_name)
return translatable_fields
def _get_translatable_field_filters(self, locale: str):
"""Generate filters for filtering TJSON objects that has necessary locale."""
return {f'{field}__has_key': locale for field in self._get_translatable_fields()}
def has_translation(self, locale: str):
"""Filter objects by locale from request."""
return self.filter(**self._get_translatable_field_filters(locale))

View File

@ -74,7 +74,7 @@ PROJECT_APPS = [
'comment.apps.CommentConfig',
'favorites.apps.FavoritesConfig',
'rating.apps.RatingConfig',
'transfer.apps.TransferConfig',
# 'transfer.apps.TransferConfig',
'tag.apps.TagConfig',
'product.apps.ProductConfig',
]
@ -157,16 +157,16 @@ DATABASES = {
'HOST': os.environ.get('DB_HOSTNAME'),
'PORT': os.environ.get('DB_PORT'),
},
'legacy': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '172.17.0.1',
# 'HOST': '172.23.0.1',
# 'HOST': 'mysql_db',
'PORT': 3306,
'NAME': 'dev',
'USER': 'dev',
'PASSWORD': 'octosecret123'
}
# 'legacy': {
# 'ENGINE': 'django.db.backends.mysql',
# # 'HOST': '172.17.0.1',
# # 'HOST': '172.23.0.1',
# 'HOST': 'mysql_db',
# 'PORT': 3306,
# 'NAME': 'dev',
# 'USER': 'dev',
# 'PASSWORD': 'octosecret123'
# }
}
@ -262,8 +262,8 @@ OAUTH2_SOCIAL_AUTH_GRANT_TYPE = 'convert_token'
OAUTH2_PROVIDER_APPLICATION_MODEL = 'authorization.Application'
# Facebook configuration
SOCIAL_AUTH_FACEBOOK_KEY = '386843648701452'
SOCIAL_AUTH_FACEBOOK_SECRET = 'a71cf0bf3980843a8f1ea74c6d805fd7'
SOCIAL_AUTH_FACEBOOK_KEY = os.environ.get('FB_APPLICATION_ID')
SOCIAL_AUTH_FACEBOOK_SECRET = os.environ.get('FB_PRIVATE_KEY')
SOCIAL_AUTH_FACEBOOK_SCOPE = ['email', ]
SOCIAL_AUTH_FACEBOOK_PROFILE_EXTRA_PARAMS = {
'fields': 'id, name, email',
@ -490,3 +490,8 @@ PHONENUMBER_DB_FORMAT = 'NATIONAL'
PHONENUMBER_DEFAULT_REGION = "FR"
FALLBACK_LOCALE = 'en-GB'
# TMP TODO remove it later
# Временный хардкод для демонстрации 4 ноября, потом удалить!
ESTABLISHMENT_CHOSEN_TAGS = ['gastronomic', 'en_vogue', 'terrace', 'streetfood', 'business', 'bar_cocktail', 'brunch', 'pop']
NEWS_CHOSEN_TAGS = ['eat', 'drink', 'cook', 'style', 'international', 'event', 'partnership']

View File

@ -6,6 +6,8 @@ from sentry_sdk.integrations.django import DjangoIntegration
ALLOWED_HOSTS = ['gm.id-east.ru', '95.213.204.126', '0.0.0.0']
CSRF_TRUSTED_ORIGINS = ['.gm.id-east.ru', ]
SEND_SMS = False
SMS_CODE_SHOW = True
USE_CELERY = True
@ -38,7 +40,7 @@ sentry_sdk.init(
# TMP ( TODO remove it later)
# Временный хардкод для демонстрации 4 ноября, потом удалить!
HARDCODED_INTERNATIONAL_NEWS_IDS = [8, 9, 10, 11, 15, 17]
HARDCODED_INTERNATIONAL_NEWS_IDS = [1460, 1471, 1482, 1484, 1611, 1612]
# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
@ -52,12 +54,16 @@ DATABASES = {
'HOST': os.environ.get('DB_HOSTNAME'),
'PORT': os.environ.get('DB_PORT'),
},
'legacy': {
'ENGINE': 'django.db.backends.mysql',
'HOST': os.environ.get('MYSQL_HOSTNAME'),
'PORT': os.environ.get('MYSQL_PORT'),
'NAME': os.environ.get('MYSQL_DATABASE'),
'USER': os.environ.get('MYSQL_USER'),
'PASSWORD': os.environ.get('MYSQL_PASSWORD')
}
}
# 'legacy': {
# 'ENGINE': 'django.db.backends.mysql',
# 'HOST': os.environ.get('MYSQL_HOSTNAME'),
# 'PORT': os.environ.get('MYSQL_PORT'),
# 'NAME': os.environ.get('MYSQL_DATABASE'),
# 'USER': os.environ.get('MYSQL_USER'),
# 'PASSWORD': os.environ.get('MYSQL_PASSWORD')
# }
}
BROKER_URL = 'redis://localhost:6379/1'
CELERY_RESULT_BACKEND = BROKER_URL
CELERY_BROKER_URL = BROKER_URL

View File

@ -1,10 +1,67 @@
"""Production settings."""
from .base import *
from .amazon_s3 import *
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
ALLOWED_HOSTS = ['*.next.gaultmillau.com', 'api.gaultmillau.com']
CSRF_TRUSTED_ORIGINS = ['.next.gaultmillau.com', ]
SEND_SMS = False
SMS_CODE_SHOW = True
USE_CELERY = True
SCHEMA_URI = 'http'
DEFAULT_SUBDOMAIN = 'www'
SITE_DOMAIN_URI = 'gaultmillau.com'
DOMAIN_URI = 'next.gaultmillau.com'
# ELASTICSEARCH SETTINGS
ELASTICSEARCH_DSL = {
'default': {
'hosts': 'elasticsearch:9200'
}
}
ELASTICSEARCH_INDEX_NAMES = {
'search_indexes.documents.news': 'development_news', # temporarily disabled
'search_indexes.documents.establishment': 'development_establishment',
}
sentry_sdk.init(
dsn="https://35d9bb789677410ab84a822831c6314f@sentry.io/1729093",
integrations=[DjangoIntegration()]
)
# TMP ( TODO remove it later)
# Временный хардкод для демонстрации 4 ноября, потом удалить!
HARDCODED_INTERNATIONAL_NEWS_IDS = [8, 9, 10, 11, 15, 17]
# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USERNAME'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOSTNAME'),
'PORT': os.environ.get('DB_PORT'),
},
}
BROKER_URL = 'redis://localhost:6379/1'
CELERY_RESULT_BACKEND = BROKER_URL
CELERY_BROKER_URL = BROKER_URL
# Booking API configuration
GUESTONLINE_SERVICE = 'https://api.guestonline.fr/'
GUESTONLINE_TOKEN = ''
LASTABLE_SERVICE = ''
LASTABLE_TOKEN = ''
LASTABLE_PROXY = ''
LASTABLE_PROXY = ''

View File

@ -30,4 +30,4 @@ ELASTICSEARCH_INDEX_NAMES = {
# TMP ( TODO remove it later)
# Временный хардкод для демонстрации 4 ноября, потом удалить!
HARDCODED_INTERNATIONAL_NEWS_IDS = [8, 9, 10, 11, 15, 17]
HARDCODED_INTERNATIONAL_NEWS_IDS = [1460, 1471, 1482, 1484, 1611, 1612]

View File

@ -42,7 +42,7 @@ django-storages==1.7.2
sorl-thumbnail==12.5.0
mysqlclient==1.4.4
# mysqlclient==1.4.4
PyYAML==5.1.2
# temp solution