Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
5687eff646
|
|
@ -182,7 +182,7 @@ class LoginByUsernameOrEmailView(JWTGenericViewMixin, generics.GenericAPIView):
|
|||
def post(self, request, *args, **kwargs):
|
||||
"""
|
||||
## Login view.
|
||||
POST-request data
|
||||
### POST-request data
|
||||
```
|
||||
{
|
||||
"username_or_email": <str>,
|
||||
|
|
@ -191,11 +191,12 @@ class LoginByUsernameOrEmailView(JWTGenericViewMixin, generics.GenericAPIView):
|
|||
"source": <int> # 0 - Mobile, 1 - Web, 2 - All (by default used: 1)
|
||||
}
|
||||
```
|
||||
## Response
|
||||
### Response
|
||||
After a successful login, server side set up access_token and refresh token to cookies.
|
||||
In a payload of access token, the following information is being embed:
|
||||
see `User().get_user_info()`.
|
||||
|
||||
### Description
|
||||
COOKIE Max-age are determined by `remember` flag:
|
||||
if `remember` is `True` then `Max-age` parameter taken from `settings.COOKIES_MAX_AGE`
|
||||
otherwise using session COOKIE Max-age.
|
||||
|
|
@ -221,7 +222,23 @@ class LogoutView(JWTGenericViewMixin, generics.GenericAPIView):
|
|||
permission_classes = (IsAuthenticatedAndTokenIsValid, )
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""Override create method"""
|
||||
"""
|
||||
## Logout view.
|
||||
### POST-request data
|
||||
```
|
||||
{}
|
||||
```
|
||||
### Response
|
||||
If user has *valid* `access_token` in COOKIES, then response return
|
||||
blank response data with `HTTP_STATUS_CODE` *204*.
|
||||
|
||||
### Description
|
||||
For complete logout, user must provide *valid* `access_token`
|
||||
(`access_token` must be kept in `COOKIES`).
|
||||
After successful request with valid access_token, token would be expired,
|
||||
for reuse protection.
|
||||
"""
|
||||
|
||||
# Get access token objs by JTI
|
||||
access_token = AccessToken(request.COOKIES.get('access_token'))
|
||||
access_token_obj = JWTAccessToken.objects.get(jti=access_token.payload.get('jti'))
|
||||
|
|
|
|||
19
apps/comment/migrations/0009_auto_20200204_1205.py
Normal file
19
apps/comment/migrations/0009_auto_20200204_1205.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.2.7 on 2020-02-04 12:05
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('comment', '0008_comment_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='comment',
|
||||
name='mark',
|
||||
field=models.PositiveIntegerField(blank=True, default=None, null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(10)], verbose_name='Mark'),
|
||||
),
|
||||
]
|
||||
|
|
@ -17,7 +17,10 @@ class CommentLstView(generics.ListCreateAPIView):
|
|||
"establishment": Establishment.__name__.lower()
|
||||
}
|
||||
|
||||
qs = models.Comment.objects.with_base_related().filter(status=models.Comment.WAITING)
|
||||
qs = models.Comment.objects.with_base_related()
|
||||
|
||||
if "object" not in self.kwargs and "type" not in self.kwargs:
|
||||
qs = qs.filter(status=models.Comment.WAITING)
|
||||
|
||||
if "object" in self.kwargs:
|
||||
qs = qs.by_object_id(self.kwargs["object"])
|
||||
|
|
|
|||
|
|
@ -173,5 +173,5 @@ class PositionsByEstablishmentFilter(filters.FilterSet):
|
|||
def by_subtype(self, queryset, name, value):
|
||||
"""filter by establishment subtype"""
|
||||
if value not in EMPTY_VALUES:
|
||||
return queryset.by_establishment_subtype(value)
|
||||
return queryset.by_establishment_subtypes(value.split('__'))
|
||||
return queryset
|
||||
|
|
|
|||
24
apps/establishment/migrations/0098_auto_20200204_1205.py
Normal file
24
apps/establishment/migrations/0098_auto_20200204_1205.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 2.2.7 on 2020-02-04 12:05
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('establishment', '0097_merge_20200204_1135'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='company',
|
||||
name='establishment',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='companies', to='establishment.Establishment', verbose_name='establishment'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='establishmentnote',
|
||||
name='establishment',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notes', to='establishment.Establishment', verbose_name='establishment'),
|
||||
),
|
||||
]
|
||||
|
|
@ -3,7 +3,6 @@ from datetime import datetime
|
|||
from functools import reduce
|
||||
from operator import or_
|
||||
from typing import List
|
||||
from slugify import slugify
|
||||
|
||||
import elasticsearch_dsl
|
||||
from django.conf import settings
|
||||
|
|
@ -668,24 +667,6 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin,
|
|||
def __str__(self):
|
||||
return f'id:{self.id}-{self.name}'
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
slugify_slug = slugify(
|
||||
self.index_name,
|
||||
word_boundary=True
|
||||
)
|
||||
self.slug = slugify_slug
|
||||
super(Establishment, self).save(*args, **kwargs)
|
||||
|
||||
def delete(self, using=None, keep_parents=False):
|
||||
"""Overridden delete method"""
|
||||
# TODO: If this does not contradict the plan,
|
||||
# it is better to change it.
|
||||
# Just add CASCADE to Company and Note in establishment fk field.
|
||||
# Delete all related companies
|
||||
self.companies.all().delete()
|
||||
# Delete all related notes
|
||||
self.notes.all().delete()
|
||||
return super().delete(using, keep_parents)
|
||||
|
||||
@property
|
||||
def visible_tags(self):
|
||||
|
|
@ -953,7 +934,7 @@ class EstablishmentNote(ProjectBaseMixin):
|
|||
"""Note model for Establishment entity."""
|
||||
old_id = models.PositiveIntegerField(null=True, blank=True)
|
||||
text = models.TextField(verbose_name=_('text'))
|
||||
establishment = models.ForeignKey(Establishment, on_delete=models.PROTECT,
|
||||
establishment = models.ForeignKey(Establishment, on_delete=models.CASCADE,
|
||||
related_name='notes',
|
||||
verbose_name=_('establishment'))
|
||||
user = models.ForeignKey('account.User', on_delete=models.PROTECT,
|
||||
|
|
@ -989,10 +970,12 @@ class EstablishmentGallery(IntermediateGalleryModelMixin):
|
|||
class PositionQuerySet(models.QuerySet):
|
||||
|
||||
def by_establishment_type(self, value: str):
|
||||
return self.filter(establishment_type__index_name=value)
|
||||
return self.filter(Q(establishment_type__index_name=value) |
|
||||
Q(establishment_type__isnull=True, establishment_subtype__isnull=True))
|
||||
|
||||
def by_establishment_subtype(self, value: str):
|
||||
return self.filter(establishment_subtype__index_name=value)
|
||||
def by_establishment_subtypes(self, value: List[str]):
|
||||
return self.filter(Q(establishment_subtype__index_name__in=value) |
|
||||
Q(establishment_type__isnull=True, establishment_subtype__isnull=True))
|
||||
|
||||
|
||||
class Position(BaseAttributes, TranslatedFieldsMixin):
|
||||
|
|
@ -1563,7 +1546,7 @@ class CompanyQuerySet(models.QuerySet):
|
|||
class Company(ProjectBaseMixin):
|
||||
"""Establishment company model."""
|
||||
|
||||
establishment = models.ForeignKey(Establishment, on_delete=models.PROTECT,
|
||||
establishment = models.ForeignKey(Establishment, on_delete=models.CASCADE,
|
||||
related_name='companies',
|
||||
verbose_name=_('establishment'))
|
||||
name = models.CharField(max_length=255, verbose_name=_('name'))
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ from functools import lru_cache
|
|||
from django.db.models import F
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from phonenumber_field.serializerfields import PhoneNumberField
|
||||
from rest_framework import serializers
|
||||
from slugify import slugify
|
||||
|
||||
from account.serializers.common import UserShortSerializer
|
||||
from collection.models import Guide
|
||||
|
|
@ -15,6 +17,7 @@ from location.serializers import AddressDetailSerializer, TranslatedField
|
|||
from main.models import Currency
|
||||
from main.serializers import AwardSerializer
|
||||
from utils.decorators import with_base_attributes
|
||||
from utils.methods import string_random
|
||||
from utils.serializers import ImageBaseSerializer, ProjectModelSerializer, TimeZoneChoiceField, \
|
||||
PhoneMixinSerializer
|
||||
|
||||
|
|
@ -68,7 +71,7 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria
|
|||
source='contact_phones',
|
||||
allow_null=True,
|
||||
allow_empty=True,
|
||||
child=serializers.CharField(max_length=128),
|
||||
child=PhoneNumberField(),
|
||||
required=False,
|
||||
write_only=True,
|
||||
)
|
||||
|
|
@ -126,6 +129,18 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria
|
|||
if 'contact_emails' in validated_data:
|
||||
emails_list = validated_data.pop('contact_emails')
|
||||
|
||||
index_name = validated_data.get('index_name')
|
||||
if 'slug' in validated_data and index_name:
|
||||
slug = slugify(
|
||||
index_name,
|
||||
word_boundary=True
|
||||
)
|
||||
while models.Establishment.objects.filter(slug=slug).exists():
|
||||
slug = slugify(
|
||||
f'{index_name} {string_random()}',
|
||||
word_boundary=True
|
||||
)
|
||||
|
||||
instance = super().create(validated_data)
|
||||
phones_handler(phones_list, instance)
|
||||
emails_handler(emails_list, instance)
|
||||
|
|
@ -165,7 +180,15 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer):
|
|||
subtypes = model_serializers.EstablishmentSubTypeBaseSerializer(source='establishment_subtypes',
|
||||
read_only=True, many=True)
|
||||
type = model_serializers.EstablishmentTypeBaseSerializer(source='establishment_type', read_only=True)
|
||||
phones = ContactPhonesSerializer(read_only=True, many=True)
|
||||
phones = serializers.ListField(
|
||||
source='contact_phones',
|
||||
allow_null=True,
|
||||
allow_empty=True,
|
||||
child=PhoneNumberField(),
|
||||
required=False,
|
||||
write_only=True,
|
||||
)
|
||||
contact_phones = ContactPhonesSerializer(source='phones', read_only=True, many=True)
|
||||
|
||||
class Meta(model_serializers.EstablishmentBaseSerializer.Meta):
|
||||
fields = [
|
||||
|
|
@ -176,6 +199,7 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer):
|
|||
'index_name',
|
||||
'website',
|
||||
'phones',
|
||||
'contact_phones',
|
||||
'emails',
|
||||
'price_level',
|
||||
'toque_number',
|
||||
|
|
@ -196,6 +220,11 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer):
|
|||
'status_display',
|
||||
]
|
||||
|
||||
def to_representation(self, instance):
|
||||
data = super(EstablishmentRUDSerializer, self).to_representation(instance)
|
||||
data['phones'] = data.pop('contact_phones', None)
|
||||
return data
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
phones_list = []
|
||||
if 'contact_phones' in validated_data:
|
||||
|
|
@ -397,7 +426,8 @@ class EmployeeBackSerializers(PhoneMixinSerializer, serializers.ModelSerializer)
|
|||
'photo_id',
|
||||
]
|
||||
extra_kwargs = {
|
||||
'phone': {'write_only': True}
|
||||
'phone': {'write_only': True},
|
||||
'available_for_events': {'required': False}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
19
apps/product/migrations/0026_auto_20200204_1205.py
Normal file
19
apps/product/migrations/0026_auto_20200204_1205.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.2.7 on 2020-02-04 12:05
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('product', '0025_auto_20191227_1443'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='productnote',
|
||||
name='product',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notes', to='product.Product', verbose_name='product'),
|
||||
),
|
||||
]
|
||||
|
|
@ -344,12 +344,6 @@ class Product(GalleryMixin, TranslatedFieldsMixin, BaseAttributes,
|
|||
"""Override str dunder method."""
|
||||
return f'{self.name}'
|
||||
|
||||
def delete(self, using=None, keep_parents=False):
|
||||
"""Overridden delete method"""
|
||||
# Delete all related notes
|
||||
self.notes.all().delete()
|
||||
return super().delete(using, keep_parents)
|
||||
|
||||
@property
|
||||
def product_type_translated_name(self):
|
||||
"""Get translated name of product type."""
|
||||
|
|
@ -624,7 +618,7 @@ class ProductNote(ProjectBaseMixin):
|
|||
"""Note model for Product entity."""
|
||||
old_id = models.PositiveIntegerField(null=True, blank=True)
|
||||
text = models.TextField(verbose_name=_('text'))
|
||||
product = models.ForeignKey(Product, on_delete=models.PROTECT,
|
||||
product = models.ForeignKey(Product, on_delete=models.CASCADE,
|
||||
related_name='notes',
|
||||
verbose_name=_('product'))
|
||||
user = models.ForeignKey('account.User', on_delete=models.PROTECT,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user