Merge branch 'develop' into feature/permission_winery
This commit is contained in:
commit
8e63b969bf
0
apps/booking/urls/__init__.py
Normal file
0
apps/booking/urls/__init__.py
Normal file
8
apps/booking/urls/mobile.py
Normal file
8
apps/booking/urls/mobile.py
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
from booking.urls import common as common_views
|
||||||
|
app = 'booking'
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns_api = []
|
||||||
|
|
||||||
|
urlpatterns = urlpatterns_api + \
|
||||||
|
common_views.urlpatterns
|
||||||
8
apps/booking/urls/web.py
Normal file
8
apps/booking/urls/web.py
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
from booking.urls import common as common_views
|
||||||
|
app = 'booking'
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns_api = []
|
||||||
|
|
||||||
|
urlpatterns = urlpatterns_api + \
|
||||||
|
common_views.urlpatterns
|
||||||
|
|
@ -457,9 +457,15 @@ class Establishment(GalleryModelMixin, ProjectBaseMixin, URLImageMixin,
|
||||||
def visible_tags(self):
|
def visible_tags(self):
|
||||||
return super().visible_tags \
|
return super().visible_tags \
|
||||||
.exclude(category__index_name__in=['guide', 'collection', 'purchased_item',
|
.exclude(category__index_name__in=['guide', 'collection', 'purchased_item',
|
||||||
'business_tag', 'business_tags_de', 'tag'])
|
'business_tag', 'business_tags_de']) \
|
||||||
|
.exclude(value__in=['rss', 'rss_selection'])
|
||||||
# todo: recalculate toque_number
|
# todo: recalculate toque_number
|
||||||
|
|
||||||
|
@property
|
||||||
|
def visible_tags_detail(self):
|
||||||
|
"""Removes some tags from detail Establishment representation"""
|
||||||
|
return self.visible_tags.exclude(category__index_name__in=['tag'])
|
||||||
|
|
||||||
def recalculate_toque_number(self):
|
def recalculate_toque_number(self):
|
||||||
toque_number = 0
|
toque_number = 0
|
||||||
if self.address and self.public_mark:
|
if self.address and self.public_mark:
|
||||||
|
|
|
||||||
|
|
@ -232,9 +232,13 @@ class EstablishmentBackOfficeGallerySerializer(serializers.ModelSerializer):
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
"""Override validate method."""
|
"""Override validate method."""
|
||||||
establishment_pk = self.get_request_kwargs().get('pk')
|
establishment_pk = self.get_request_kwargs().get('pk')
|
||||||
|
establishment_slug = self.get_request_kwargs().get('slug')
|
||||||
|
|
||||||
|
search_kwargs = {'pk': establishment_pk} if establishment_pk else {'slug': establishment_slug}
|
||||||
|
|
||||||
image_id = self.get_request_kwargs().get('image_id')
|
image_id = self.get_request_kwargs().get('image_id')
|
||||||
|
|
||||||
establishment_qs = models.Establishment.objects.filter(pk=establishment_pk)
|
establishment_qs = models.Establishment.objects.filter(**search_kwargs)
|
||||||
image_qs = Image.objects.filter(id=image_id)
|
image_qs = Image.objects.filter(id=image_id)
|
||||||
|
|
||||||
if not establishment_qs.exists():
|
if not establishment_qs.exists():
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ from utils.serializers import ImageBaseSerializer, CarouselCreateSerializer
|
||||||
from utils.serializers import (ProjectModelSerializer, TranslatedField,
|
from utils.serializers import (ProjectModelSerializer, TranslatedField,
|
||||||
FavoritesCreateSerializer)
|
FavoritesCreateSerializer)
|
||||||
from location.serializers import EstablishmentWineRegionBaseSerializer, \
|
from location.serializers import EstablishmentWineRegionBaseSerializer, \
|
||||||
EstablishmentWineOriginBaseSerializer
|
EstablishmentWineOriginBaseSerializer
|
||||||
|
|
||||||
|
|
||||||
class ContactPhonesSerializer(serializers.ModelSerializer):
|
class ContactPhonesSerializer(serializers.ModelSerializer):
|
||||||
|
|
@ -239,6 +239,30 @@ class EstablishmentShortSerializer(serializers.ModelSerializer):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class _EstablishmentAddressShortSerializer(serializers.ModelSerializer):
|
||||||
|
"""Short serializer for establishment."""
|
||||||
|
city = CitySerializer(source='address.city', allow_null=True)
|
||||||
|
establishment_type = EstablishmentTypeGeoSerializer()
|
||||||
|
establishment_subtypes = EstablishmentSubTypeBaseSerializer(many=True)
|
||||||
|
currency = CurrencySerializer(read_only=True)
|
||||||
|
address = AddressBaseSerializer(read_only=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Meta class."""
|
||||||
|
model = models.Establishment
|
||||||
|
fields = [
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'index_name',
|
||||||
|
'slug',
|
||||||
|
'city',
|
||||||
|
'establishment_type',
|
||||||
|
'establishment_subtypes',
|
||||||
|
'currency',
|
||||||
|
'address',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class EstablishmentProductShortSerializer(serializers.ModelSerializer):
|
class EstablishmentProductShortSerializer(serializers.ModelSerializer):
|
||||||
"""SHORT Serializer for displaying info about an establishment on product page."""
|
"""SHORT Serializer for displaying info about an establishment on product page."""
|
||||||
establishment_type = EstablishmentTypeGeoSerializer()
|
establishment_type = EstablishmentTypeGeoSerializer()
|
||||||
|
|
@ -369,7 +393,7 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
|
||||||
employees = EstablishmentEmployeeSerializer(source='actual_establishment_employees',
|
employees = EstablishmentEmployeeSerializer(source='actual_establishment_employees',
|
||||||
many=True)
|
many=True)
|
||||||
address = AddressDetailSerializer(read_only=True)
|
address = AddressDetailSerializer(read_only=True)
|
||||||
|
tags = TagBaseSerializer(read_only=True, many=True, source='visible_tags_detail')
|
||||||
menu = MenuSerializers(source='menu_set', many=True, read_only=True)
|
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_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)
|
best_price_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
|
||||||
|
|
@ -522,7 +546,9 @@ class EstablishmentCarouselCreateSerializer(CarouselCreateSerializer):
|
||||||
"""Serializer to carousel object w/ model News."""
|
"""Serializer to carousel object w/ model News."""
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
establishment = models.Establishment.objects.filter(pk=self.pk).first()
|
search_kwargs = {'pk': self.pk} if self.pk else {'slug': self.slug}
|
||||||
|
|
||||||
|
establishment = models.Establishment.objects.filter(**search_kwargs).first()
|
||||||
if not establishment:
|
if not establishment:
|
||||||
raise serializers.ValidationError({'detail': _('Object not found.')})
|
raise serializers.ValidationError({'detail': _('Object not found.')})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -157,18 +157,18 @@ class EstablishmentBackTests(BaseTestCase):
|
||||||
response = self.client.post('/api/back/establishments/', data=data, format='json')
|
response = self.client.post('/api/back/establishments/', data=data, format='json')
|
||||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
|
|
||||||
response = self.client.get(f'/api/back/establishments/{self.establishment.id}/', format='json')
|
response = self.client.get(f'/api/back/establishments/slug/{self.establishment.slug}/', format='json')
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
update_data = {
|
update_data = {
|
||||||
'name': 'Test new establishment'
|
'name': 'Test new establishment'
|
||||||
}
|
}
|
||||||
|
|
||||||
response = self.client.patch(f'/api/back/establishments/{self.establishment.id}/',
|
response = self.client.patch(f'/api/back/establishments/slug/{self.establishment.slug}/',
|
||||||
data=update_data)
|
data=update_data)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
response = self.client.delete(f'/api/back/establishments/{self.establishment.id}/',
|
response = self.client.delete(f'/api/back/establishments/slug/{self.establishment.slug}/',
|
||||||
format='json')
|
format='json')
|
||||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
|
@ -425,22 +425,22 @@ class EstablishmentShedulerTests(ChildTestCase):
|
||||||
'weekday': 1
|
'weekday': 1
|
||||||
}
|
}
|
||||||
|
|
||||||
response = self.client.post(f'/api/back/establishments/{self.establishment.id}/schedule/', data=data)
|
response = self.client.post(f'/api/back/establishments/slug/{self.establishment.slug}/schedule/', data=data)
|
||||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
schedule = response.data
|
schedule = response.data
|
||||||
|
|
||||||
response = self.client.get(f'/api/back/establishments/{self.establishment.id}/schedule/{schedule["id"]}/')
|
response = self.client.get(f'/api/back/establishments/slug/{self.establishment.slug}/schedule/{schedule["id"]}/')
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
update_data = {
|
update_data = {
|
||||||
'weekday': 2
|
'weekday': 2
|
||||||
}
|
}
|
||||||
|
|
||||||
response = self.client.patch(f'/api/back/establishments/{self.establishment.id}/schedule/{schedule["id"]}/',
|
response = self.client.patch(f'/api/back/establishments/slug/{self.establishment.slug}/schedule/{schedule["id"]}/',
|
||||||
data=update_data)
|
data=update_data)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
response = self.client.delete(f'/api/back/establishments/{self.establishment.id}/schedule/{schedule["id"]}/')
|
response = self.client.delete(f'/api/back/establishments/slug/{self.establishment.slug}/schedule/{schedule["id"]}/')
|
||||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -537,8 +537,8 @@ class EstablishmentCarouselTests(ChildTestCase):
|
||||||
"object_id": self.establishment.id
|
"object_id": self.establishment.id
|
||||||
}
|
}
|
||||||
|
|
||||||
response = self.client.post(f'/api/back/establishments/{self.establishment.id}/carousels/', data=data)
|
response = self.client.post(f'/api/back/establishments/slug/{self.establishment.slug}/carousels/', data=data)
|
||||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
|
|
||||||
response = self.client.delete(f'/api/back/establishments/{self.establishment.id}/carousels/')
|
response = self.client.delete(f'/api/back/establishments/slug/{self.establishment.slug}/carousels/')
|
||||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||||
|
|
|
||||||
|
|
@ -8,25 +8,25 @@ app_name = 'establishment'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.EstablishmentListCreateView.as_view(), name='list'),
|
path('', views.EstablishmentListCreateView.as_view(), name='list'),
|
||||||
path('<int:pk>/', views.EstablishmentRUDView.as_view(), name='detail'),
|
path('slug/<slug:slug>/', views.EstablishmentRUDView.as_view(), name='detail'),
|
||||||
path('<int:pk>/carousels/', views.EstablishmentCarouselCreateDestroyView.as_view(),
|
path('slug/<slug:slug>/carousels/', views.EstablishmentCarouselCreateDestroyView.as_view(),
|
||||||
name='create-destroy-carousels'),
|
name='create-destroy-carousels'),
|
||||||
path('<int:pk>/schedule/<int:schedule_id>/', views.EstablishmentScheduleRUDView.as_view(),
|
path('slug/<slug:slug>/schedule/<int:schedule_id>/', views.EstablishmentScheduleRUDView.as_view(),
|
||||||
name='schedule-rud'),
|
name='schedule-rud'),
|
||||||
path('<int:pk>/schedule/', views.EstablishmentScheduleCreateView.as_view(),
|
path('slug/<slug:slug>/schedule/', views.EstablishmentScheduleCreateView.as_view(),
|
||||||
name='schedule-create'),
|
name='schedule-create'),
|
||||||
path('<int:pk>/gallery/', views.EstablishmentGalleryListView.as_view(),
|
path('slug/<slug:slug>/gallery/', views.EstablishmentGalleryListView.as_view(),
|
||||||
name='gallery-list'),
|
name='gallery-list'),
|
||||||
path('<int:pk>/gallery/<int:image_id>/',
|
path('slug/<slug:slug>/gallery/<int:image_id>/',
|
||||||
views.EstablishmentGalleryCreateDestroyView.as_view(),
|
views.EstablishmentGalleryCreateDestroyView.as_view(),
|
||||||
name='gallery-create-destroy'),
|
name='gallery-create-destroy'),
|
||||||
path('<int:pk>/companies/', views.EstablishmentCompanyListCreateView.as_view(),
|
path('slug/<slug:slug>/companies/', views.EstablishmentCompanyListCreateView.as_view(),
|
||||||
name='company-list-create'),
|
name='company-list-create'),
|
||||||
path('<int:pk>/companies/<int:company_pk>/', views.EstablishmentCompanyRUDView.as_view(),
|
path('slug/<slug:slug>/companies/<int:company_pk>/', views.EstablishmentCompanyRUDView.as_view(),
|
||||||
name='company-rud'),
|
name='company-rud'),
|
||||||
path('<int:pk>/notes/', views.EstablishmentNoteListCreateView.as_view(),
|
path('slug/<slug:slug>/notes/', views.EstablishmentNoteListCreateView.as_view(),
|
||||||
name='note-list-create'),
|
name='note-list-create'),
|
||||||
path('<int:pk>/notes/<int:note_pk>/', views.EstablishmentNoteRUDView.as_view(),
|
path('slug/<slug:slug>/notes/<int:note_pk>/', views.EstablishmentNoteRUDView.as_view(),
|
||||||
name='note-rud'),
|
name='note-rud'),
|
||||||
path('menus/', views.MenuListCreateView.as_view(), name='menu-list'),
|
path('menus/', views.MenuListCreateView.as_view(), name='menu-list'),
|
||||||
path('menus/<int:pk>/', views.MenuRUDView.as_view(), name='menu-rud'),
|
path('menus/<int:pk>/', views.MenuRUDView.as_view(), name='menu-rud'),
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAP
|
||||||
|
|
||||||
|
|
||||||
class EstablishmentRUDView(generics.RetrieveUpdateDestroyAPIView):
|
class EstablishmentRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
lookup_field = 'slug'
|
||||||
queryset = models.Establishment.objects.all()
|
queryset = models.Establishment.objects.all()
|
||||||
serializer_class = serializers.EstablishmentRUDSerializer
|
serializer_class = serializers.EstablishmentRUDSerializer
|
||||||
permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager]
|
permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager]
|
||||||
|
|
@ -38,6 +39,7 @@ class EstablishmentRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
|
||||||
class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView):
|
class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
"""Establishment schedule RUD view"""
|
"""Establishment schedule RUD view"""
|
||||||
|
lookup_field = 'slug'
|
||||||
serializer_class = ScheduleRUDSerializer
|
serializer_class = ScheduleRUDSerializer
|
||||||
permission_classes = [IsWineryReviewer |IsEstablishmentManager]
|
permission_classes = [IsWineryReviewer |IsEstablishmentManager]
|
||||||
|
|
||||||
|
|
@ -45,11 +47,11 @@ class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
"""
|
"""
|
||||||
Returns the object the view is displaying.
|
Returns the object the view is displaying.
|
||||||
"""
|
"""
|
||||||
establishment_pk = self.kwargs['pk']
|
establishment_slug = self.kwargs['slug']
|
||||||
schedule_id = self.kwargs['schedule_id']
|
schedule_id = self.kwargs['schedule_id']
|
||||||
|
|
||||||
establishment = get_object_or_404(klass=models.Establishment.objects.all(),
|
establishment = get_object_or_404(klass=models.Establishment.objects.all(),
|
||||||
pk=establishment_pk)
|
slug=establishment_slug)
|
||||||
schedule = get_object_or_404(klass=establishment.schedule,
|
schedule = get_object_or_404(klass=establishment.schedule,
|
||||||
id=schedule_id)
|
id=schedule_id)
|
||||||
|
|
||||||
|
|
@ -62,6 +64,7 @@ class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
|
|
||||||
class EstablishmentScheduleCreateView(generics.CreateAPIView):
|
class EstablishmentScheduleCreateView(generics.CreateAPIView):
|
||||||
"""Establishment schedule Create view"""
|
"""Establishment schedule Create view"""
|
||||||
|
lookup_field = 'slug'
|
||||||
serializer_class = ScheduleCreateSerializer
|
serializer_class = ScheduleCreateSerializer
|
||||||
queryset = Timetable.objects.all()
|
queryset = Timetable.objects.all()
|
||||||
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
|
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
|
||||||
|
|
@ -210,6 +213,7 @@ class EstablishmentSubtypeRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
class EstablishmentGalleryCreateDestroyView(EstablishmentMixinViews,
|
class EstablishmentGalleryCreateDestroyView(EstablishmentMixinViews,
|
||||||
CreateDestroyGalleryViewMixin):
|
CreateDestroyGalleryViewMixin):
|
||||||
"""Resource for a create|destroy gallery for establishment for back-office users."""
|
"""Resource for a create|destroy gallery for establishment for back-office users."""
|
||||||
|
lookup_field = 'slug'
|
||||||
serializer_class = serializers.EstablishmentBackOfficeGallerySerializer
|
serializer_class = serializers.EstablishmentBackOfficeGallerySerializer
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
|
|
@ -218,7 +222,7 @@ class EstablishmentGalleryCreateDestroyView(EstablishmentMixinViews,
|
||||||
"""
|
"""
|
||||||
establishment_qs = self.filter_queryset(self.get_queryset())
|
establishment_qs = self.filter_queryset(self.get_queryset())
|
||||||
|
|
||||||
establishment = get_object_or_404(establishment_qs, pk=self.kwargs.get('pk'))
|
establishment = get_object_or_404(establishment_qs, slug=self.kwargs.get('slug'))
|
||||||
gallery = get_object_or_404(establishment.establishment_gallery,
|
gallery = get_object_or_404(establishment.establishment_gallery,
|
||||||
image_id=self.kwargs.get('image_id'))
|
image_id=self.kwargs.get('image_id'))
|
||||||
|
|
||||||
|
|
@ -231,12 +235,13 @@ class EstablishmentGalleryCreateDestroyView(EstablishmentMixinViews,
|
||||||
class EstablishmentGalleryListView(EstablishmentMixinViews,
|
class EstablishmentGalleryListView(EstablishmentMixinViews,
|
||||||
generics.ListAPIView):
|
generics.ListAPIView):
|
||||||
"""Resource for returning gallery for establishment for back-office users."""
|
"""Resource for returning gallery for establishment for back-office users."""
|
||||||
|
lookup_field = 'slug'
|
||||||
serializer_class = serializers.ImageBaseSerializer
|
serializer_class = serializers.ImageBaseSerializer
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
"""Override get_object method."""
|
"""Override get_object method."""
|
||||||
qs = super(EstablishmentGalleryListView, self).get_queryset()
|
qs = super(EstablishmentGalleryListView, self).get_queryset()
|
||||||
establishment = get_object_or_404(qs, pk=self.kwargs.get('pk'))
|
establishment = get_object_or_404(qs, slug=self.kwargs.get('slug'))
|
||||||
|
|
||||||
# May raise a permission denied
|
# May raise a permission denied
|
||||||
self.check_object_permissions(self.request, establishment)
|
self.check_object_permissions(self.request, establishment)
|
||||||
|
|
@ -252,6 +257,7 @@ class EstablishmentCompanyListCreateView(EstablishmentMixinViews,
|
||||||
generics.ListCreateAPIView):
|
generics.ListCreateAPIView):
|
||||||
"""List|Create establishment company view."""
|
"""List|Create establishment company view."""
|
||||||
|
|
||||||
|
lookup_field = 'slug'
|
||||||
serializer_class = serializers.EstablishmentCompanyListCreateSerializer
|
serializer_class = serializers.EstablishmentCompanyListCreateSerializer
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
|
|
@ -259,7 +265,7 @@ class EstablishmentCompanyListCreateView(EstablishmentMixinViews,
|
||||||
establishment_qs = models.Establishment.objects.all()
|
establishment_qs = models.Establishment.objects.all()
|
||||||
filtered_ad_qs = self.filter_queryset(establishment_qs)
|
filtered_ad_qs = self.filter_queryset(establishment_qs)
|
||||||
|
|
||||||
establishment = get_object_or_404(filtered_ad_qs, pk=self.kwargs.get('pk'))
|
establishment = get_object_or_404(filtered_ad_qs, slug=self.kwargs.get('slug'))
|
||||||
|
|
||||||
# May raise a permission denied
|
# May raise a permission denied
|
||||||
self.check_object_permissions(self.request, establishment)
|
self.check_object_permissions(self.request, establishment)
|
||||||
|
|
@ -275,6 +281,7 @@ class EstablishmentCompanyRUDView(EstablishmentMixinViews,
|
||||||
generics.RetrieveUpdateDestroyAPIView):
|
generics.RetrieveUpdateDestroyAPIView):
|
||||||
"""Create|Retrieve|Update|Destroy establishment company view."""
|
"""Create|Retrieve|Update|Destroy establishment company view."""
|
||||||
|
|
||||||
|
lookup_field = 'slug'
|
||||||
serializer_class = serializers.CompanyBaseSerializer
|
serializer_class = serializers.CompanyBaseSerializer
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
|
|
@ -282,7 +289,7 @@ class EstablishmentCompanyRUDView(EstablishmentMixinViews,
|
||||||
establishment_qs = models.Establishment.objects.all()
|
establishment_qs = models.Establishment.objects.all()
|
||||||
filtered_ad_qs = self.filter_queryset(establishment_qs)
|
filtered_ad_qs = self.filter_queryset(establishment_qs)
|
||||||
|
|
||||||
establishment = get_object_or_404(filtered_ad_qs, pk=self.kwargs.get('pk'))
|
establishment = get_object_or_404(filtered_ad_qs, slug=self.kwargs.get('slug'))
|
||||||
company = get_object_or_404(establishment.companies.all(), pk=self.kwargs.get('company_pk'))
|
company = get_object_or_404(establishment.companies.all(), pk=self.kwargs.get('company_pk'))
|
||||||
|
|
||||||
# May raise a permission denied
|
# May raise a permission denied
|
||||||
|
|
@ -295,6 +302,7 @@ class EstablishmentNoteListCreateView(EstablishmentMixinViews,
|
||||||
generics.ListCreateAPIView):
|
generics.ListCreateAPIView):
|
||||||
"""Retrieve|Update|Destroy establishment note view."""
|
"""Retrieve|Update|Destroy establishment note view."""
|
||||||
|
|
||||||
|
lookup_field = 'slug'
|
||||||
serializer_class = serializers.EstablishmentNoteListCreateSerializer
|
serializer_class = serializers.EstablishmentNoteListCreateSerializer
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
|
|
@ -302,7 +310,7 @@ class EstablishmentNoteListCreateView(EstablishmentMixinViews,
|
||||||
establishment_qs = models.Establishment.objects.all()
|
establishment_qs = models.Establishment.objects.all()
|
||||||
filtered_establishment_qs = self.filter_queryset(establishment_qs)
|
filtered_establishment_qs = self.filter_queryset(establishment_qs)
|
||||||
|
|
||||||
establishment = get_object_or_404(filtered_establishment_qs, pk=self.kwargs.get('pk'))
|
establishment = get_object_or_404(filtered_establishment_qs, slug=self.kwargs.get('slug'))
|
||||||
|
|
||||||
# May raise a permission denied
|
# May raise a permission denied
|
||||||
self.check_object_permissions(self.request, establishment)
|
self.check_object_permissions(self.request, establishment)
|
||||||
|
|
@ -318,6 +326,7 @@ class EstablishmentNoteRUDView(EstablishmentMixinViews,
|
||||||
generics.RetrieveUpdateDestroyAPIView):
|
generics.RetrieveUpdateDestroyAPIView):
|
||||||
"""Create|Retrieve|Update|Destroy establishment note view."""
|
"""Create|Retrieve|Update|Destroy establishment note view."""
|
||||||
|
|
||||||
|
lookup_field = 'slug'
|
||||||
serializer_class = serializers.EstablishmentNoteBaseSerializer
|
serializer_class = serializers.EstablishmentNoteBaseSerializer
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
|
|
@ -325,7 +334,7 @@ class EstablishmentNoteRUDView(EstablishmentMixinViews,
|
||||||
establishment_qs = models.Establishment.objects.all()
|
establishment_qs = models.Establishment.objects.all()
|
||||||
filtered_establishment_qs = self.filter_queryset(establishment_qs)
|
filtered_establishment_qs = self.filter_queryset(establishment_qs)
|
||||||
|
|
||||||
establishment = get_object_or_404(filtered_establishment_qs, pk=self.kwargs.get('pk'))
|
establishment = get_object_or_404(filtered_establishment_qs, slug=self.kwargs.get('slug'))
|
||||||
note = get_object_or_404(establishment.notes.all(), pk=self.kwargs['note_pk'])
|
note = get_object_or_404(establishment.notes.all(), pk=self.kwargs['note_pk'])
|
||||||
|
|
||||||
# May raise a permission denied
|
# May raise a permission denied
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@ class EstablishmentFavoritesCreateDestroyView(FavoritesCreateDestroyMixinView):
|
||||||
class EstablishmentCarouselCreateDestroyView(CarouselCreateDestroyMixinView):
|
class EstablishmentCarouselCreateDestroyView(CarouselCreateDestroyMixinView):
|
||||||
"""View for create/destroy establishment from carousel."""
|
"""View for create/destroy establishment from carousel."""
|
||||||
|
|
||||||
|
lookup_field = 'slug'
|
||||||
_model = models.Establishment
|
_model = models.Establishment
|
||||||
serializer_class = serializers.EstablishmentCarouselCreateSerializer
|
serializer_class = serializers.EstablishmentCarouselCreateSerializer
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,9 @@ class Command(BaseCommand):
|
||||||
new_address = Address.objects.filter(old_id=idx).first()
|
new_address = Address.objects.filter(old_id=idx).first()
|
||||||
if new_address:
|
if new_address:
|
||||||
new_address.number = 0
|
new_address.number = 0
|
||||||
|
new_address.street_name_2 = ''
|
||||||
new_address.street_name_1 = address
|
new_address.street_name_1 = address
|
||||||
update_address.append(new_address)
|
update_address.append(new_address)
|
||||||
|
|
||||||
Address.objects.bulk_update(update_address, ['number', 'street_name_1'])
|
Address.objects.bulk_update(update_address, ['number', 'street_name_1', 'street_name_2'])
|
||||||
self.stdout.write(self.style.WARNING(f'Updated addresses: {len(update_address)}'))
|
self.stdout.write(self.style.WARNING(f'Updated addresses: {len(update_address)}'))
|
||||||
|
|
|
||||||
17
apps/news/management/commands/rm_empty_images.py
Normal file
17
apps/news/management/commands/rm_empty_images.py
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from news.models import News
|
||||||
|
import re
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Removes empty img html tags from news description'
|
||||||
|
|
||||||
|
relative_img_regex = re.compile(r'\<img.+src=(?!https?:\/\/)([^\/].+?)[\"|\']>', re.I)
|
||||||
|
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
for news in News.objects.all():
|
||||||
|
if isinstance(news.description, dict):
|
||||||
|
news.description = {locale: self.relative_img_regex.sub('', rich_text)
|
||||||
|
for locale, rich_text in news.description.items()}
|
||||||
|
self.stdout.write(self.style.WARNING(f'Replaced {news} empty img html tags...\n'))
|
||||||
|
news.save()
|
||||||
|
|
@ -8,7 +8,7 @@ from partner.serializers import common as serializers
|
||||||
# Mixins
|
# Mixins
|
||||||
class PartnerViewMixin(generics.GenericAPIView):
|
class PartnerViewMixin(generics.GenericAPIView):
|
||||||
"""View mixin for Partner views"""
|
"""View mixin for Partner views"""
|
||||||
queryset = models.Partner.objects.all()
|
queryset = models.Partner.objects.distinct("name")
|
||||||
|
|
||||||
|
|
||||||
# Views
|
# Views
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ class ProductFilterSet(filters.FilterSet):
|
||||||
"""Product filter set."""
|
"""Product filter set."""
|
||||||
|
|
||||||
establishment_id = filters.NumberFilter()
|
establishment_id = filters.NumberFilter()
|
||||||
|
current_product = filters.CharFilter(method='without_current_product')
|
||||||
product_type = filters.CharFilter(method='by_product_type')
|
product_type = filters.CharFilter(method='by_product_type')
|
||||||
product_subtype = filters.CharFilter(method='by_product_subtype')
|
product_subtype = filters.CharFilter(method='by_product_subtype')
|
||||||
|
|
||||||
|
|
@ -21,6 +22,11 @@ class ProductFilterSet(filters.FilterSet):
|
||||||
'product_subtype',
|
'product_subtype',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def without_current_product(self, queryset, name, value):
|
||||||
|
if value not in EMPTY_VALUES:
|
||||||
|
return queryset.without_current_product(value)
|
||||||
|
return queryset
|
||||||
|
|
||||||
def by_product_type(self, queryset, name, value):
|
def by_product_type(self, queryset, name, value):
|
||||||
if value not in EMPTY_VALUES:
|
if value not in EMPTY_VALUES:
|
||||||
return queryset.by_product_type(value)
|
return queryset.by_product_type(value)
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,11 @@ class ProductQuerySet(models.QuerySet):
|
||||||
def wines(self):
|
def wines(self):
|
||||||
return self.filter(type__index_name__icontains=ProductType.WINE)
|
return self.filter(type__index_name__icontains=ProductType.WINE)
|
||||||
|
|
||||||
|
def without_current_product(self, current_product: str):
|
||||||
|
"""Exclude by current product."""
|
||||||
|
kwargs = {'pk': int(current_product)} if current_product.isdigit() else {'slug': current_product}
|
||||||
|
return self.exclude(**kwargs)
|
||||||
|
|
||||||
def by_product_type(self, product_type: str):
|
def by_product_type(self, product_type: str):
|
||||||
"""Filter by type."""
|
"""Filter by type."""
|
||||||
return self.filter(product_type__index_name__icontains=product_type)
|
return self.filter(product_type__index_name__icontains=product_type)
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,15 @@ from rest_framework import serializers
|
||||||
|
|
||||||
from comment.models import Comment
|
from comment.models import Comment
|
||||||
from comment.serializers import CommentSerializer
|
from comment.serializers import CommentSerializer
|
||||||
from establishment.serializers import EstablishmentShortSerializer, EstablishmentProductSerializer, EstablishmentProductShortSerializer
|
from establishment.serializers import EstablishmentProductShortSerializer
|
||||||
from gallery.models import Image
|
from establishment.serializers.common import _EstablishmentAddressShortSerializer
|
||||||
|
from location.serializers import WineOriginRegionBaseSerializer, WineOriginBaseSerializer
|
||||||
|
from main.serializers import AwardSerializer
|
||||||
from product import models
|
from product import models
|
||||||
from review.serializers import ReviewShortSerializer
|
from review.serializers import ReviewShortSerializer
|
||||||
|
from tag.serializers import TagBaseSerializer, TagCategoryProductSerializer
|
||||||
from utils import exceptions as utils_exceptions
|
from utils import exceptions as utils_exceptions
|
||||||
from utils.serializers import TranslatedField, FavoritesCreateSerializer, ImageBaseSerializer
|
from utils.serializers import TranslatedField, FavoritesCreateSerializer, ImageBaseSerializer
|
||||||
from main.serializers import AwardSerializer
|
|
||||||
from location.serializers import WineOriginRegionBaseSerializer, WineOriginBaseSerializer
|
|
||||||
from tag.serializers import TagBaseSerializer, TagCategoryProductSerializer
|
|
||||||
|
|
||||||
|
|
||||||
class ProductTagSerializer(TagBaseSerializer):
|
class ProductTagSerializer(TagBaseSerializer):
|
||||||
|
|
@ -119,7 +119,7 @@ class ProductBaseSerializer(serializers.ModelSerializer):
|
||||||
class ProductDetailSerializer(ProductBaseSerializer):
|
class ProductDetailSerializer(ProductBaseSerializer):
|
||||||
"""Product detail serializer."""
|
"""Product detail serializer."""
|
||||||
description_translated = TranslatedField()
|
description_translated = TranslatedField()
|
||||||
establishment_detail = EstablishmentShortSerializer(source='establishment', read_only=True)
|
establishment_detail = _EstablishmentAddressShortSerializer(source='establishment', read_only=True)
|
||||||
review = ReviewShortSerializer(source='last_published_review', read_only=True)
|
review = ReviewShortSerializer(source='last_published_review', read_only=True)
|
||||||
awards = AwardSerializer(many=True, read_only=True)
|
awards = AwardSerializer(many=True, read_only=True)
|
||||||
classifications = ProductClassificationBaseSerializer(many=True, read_only=True)
|
classifications = ProductClassificationBaseSerializer(many=True, read_only=True)
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,14 @@ class ScheduleRUDSerializer(serializers.ModelSerializer):
|
||||||
.parser_context.get('view')\
|
.parser_context.get('view')\
|
||||||
.kwargs.get('pk')
|
.kwargs.get('pk')
|
||||||
|
|
||||||
|
establishment_slug = self.context.get('request')\
|
||||||
|
.parser_context.get('view')\
|
||||||
|
.kwargs.get('slug')
|
||||||
|
|
||||||
|
search_kwargs = {'pk': establishment_pk} if establishment_pk else {'slug': establishment_slug}
|
||||||
|
|
||||||
# Check if establishment exists.
|
# Check if establishment exists.
|
||||||
establishment_qs = Establishment.objects.filter(pk=establishment_pk)
|
establishment_qs = Establishment.objects.filter(**search_kwargs)
|
||||||
if not establishment_qs.exists():
|
if not establishment_qs.exists():
|
||||||
raise serializers.ValidationError({'detail': _('Establishment not found.')})
|
raise serializers.ValidationError({'detail': _('Establishment not found.')})
|
||||||
attrs['establishment'] = establishment_qs.first()
|
attrs['establishment'] = establishment_qs.first()
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,10 @@ class CarouselCreateSerializer(serializers.ModelSerializer):
|
||||||
def pk(self):
|
def pk(self):
|
||||||
return self.request.parser_context.get('kwargs').get('pk')
|
return self.request.parser_context.get('kwargs').get('pk')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def slug(self):
|
||||||
|
return self.request.parser_context.get('kwargs').get('slug')
|
||||||
|
|
||||||
|
|
||||||
class RecursiveFieldSerializer(serializers.Serializer):
|
class RecursiveFieldSerializer(serializers.Serializer):
|
||||||
def to_representation(self, value):
|
def to_representation(self, value):
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,11 @@ class CarouselCreateDestroyMixinView(BaseCreateDestroyMixinView):
|
||||||
lookup_field = 'id'
|
lookup_field = 'id'
|
||||||
|
|
||||||
def get_base_object(self):
|
def get_base_object(self):
|
||||||
return get_object_or_404(self._model, id=self.kwargs['pk'])
|
establishment_pk = self.kwargs.get('pk')
|
||||||
|
establishment_slug = self.kwargs.get('slug')
|
||||||
|
|
||||||
|
search_kwargs = {'id': establishment_pk} if establishment_pk else {'slug': establishment_slug}
|
||||||
|
return get_object_or_404(self._model, **search_kwargs)
|
||||||
|
|
||||||
def get_object(self):
|
def get_object(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,9 @@ services:
|
||||||
MYSQL_ROOT_PASSWORD: rootPassword
|
MYSQL_ROOT_PASSWORD: rootPassword
|
||||||
volumes:
|
volumes:
|
||||||
- gm-mysql_db:/var/lib/mysql
|
- gm-mysql_db:/var/lib/mysql
|
||||||
|
- .:/code
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# PostgreSQL database
|
# PostgreSQL database
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,4 @@
|
||||||
./manage.py transfer --inquiries
|
./manage.py transfer --inquiries
|
||||||
./manage.py transfer --assemblage
|
./manage.py transfer --assemblage
|
||||||
./manage.py transfer --purchased_plaques
|
./manage.py transfer --purchased_plaques
|
||||||
|
./manage.py rm_empty_images
|
||||||
|
|
@ -414,10 +414,10 @@ SORL_THUMBNAIL_ALIASES = {
|
||||||
SIMPLE_JWT = {
|
SIMPLE_JWT = {
|
||||||
# Increase access token lifetime b.c. front-end dev's cant send multiple
|
# Increase access token lifetime b.c. front-end dev's cant send multiple
|
||||||
# requests to API in one HTTP request.
|
# requests to API in one HTTP request.
|
||||||
'ACCESS_TOKEN_LIFETIME': timedelta(days=30),
|
'ACCESS_TOKEN_LIFETIME': timedelta(days=182),
|
||||||
'ACCESS_TOKEN_LIFETIME_SECONDS': 21600, # 6 hours in seconds
|
'ACCESS_TOKEN_LIFETIME_SECONDS': 15770000, # 6 months
|
||||||
'REFRESH_TOKEN_LIFETIME': timedelta(days=30),
|
'REFRESH_TOKEN_LIFETIME': timedelta(days=182),
|
||||||
'REFRESH_TOKEN_LIFETIME_SECONDS': 2592000, # 30 days in seconds
|
'REFRESH_TOKEN_LIFETIME_SECONDS': 15770000, # 6 months
|
||||||
'ROTATE_REFRESH_TOKENS': True,
|
'ROTATE_REFRESH_TOKENS': True,
|
||||||
'BLACKLIST_AFTER_ROTATION': True,
|
'BLACKLIST_AFTER_ROTATION': True,
|
||||||
|
|
||||||
|
|
@ -453,7 +453,7 @@ NOTIFICATION_PASSWORD_TEMPLATE = 'account/password_change_email.html'
|
||||||
|
|
||||||
|
|
||||||
# COOKIES
|
# COOKIES
|
||||||
COOKIES_MAX_AGE = 2628000 # 30 days
|
COOKIES_MAX_AGE = 15730000 # 6 months
|
||||||
SESSION_COOKIE_SAMESITE = None
|
SESSION_COOKIE_SAMESITE = None
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ from django.urls import path, include
|
||||||
app_name = 'mobile'
|
app_name = 'mobile'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path('booking/', include('booking.urls.web')),
|
||||||
path('establishments/', include('establishment.urls.mobile')),
|
path('establishments/', include('establishment.urls.mobile')),
|
||||||
path('location/', include('location.urls.mobile')),
|
path('location/', include('location.urls.mobile')),
|
||||||
path('main/', include('main.urls.mobile')),
|
path('main/', include('main.urls.mobile')),
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ app_name = 'web'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('account/', include('account.urls.web')),
|
path('account/', include('account.urls.web')),
|
||||||
path('booking/', include('booking.urls')),
|
path('booking/', include('booking.urls.web')),
|
||||||
path('re_blocks/', include('advertisement.urls.web')),
|
path('re_blocks/', include('advertisement.urls.web')),
|
||||||
path('collections/', include('collection.urls.web')),
|
path('collections/', include('collection.urls.web')),
|
||||||
path('establishments/', include('establishment.urls.web')),
|
path('establishments/', include('establishment.urls.web')),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user