added field phone to User model, change establishment transfer, added filters (full-text search, role_country_code, country_code), change account serializers
This commit is contained in:
parent
6d627ac240
commit
de78ee5d6e
|
|
@ -25,13 +25,13 @@ class UserAdmin(BaseUserAdmin):
|
||||||
'is_staff', 'is_superuser', 'email_confirmed')
|
'is_staff', 'is_superuser', 'email_confirmed')
|
||||||
list_filter = ('is_active', 'is_staff', 'is_superuser', 'email_confirmed',
|
list_filter = ('is_active', 'is_staff', 'is_superuser', 'email_confirmed',
|
||||||
'groups',)
|
'groups',)
|
||||||
search_fields = ('email', 'first_name', 'last_name')
|
search_fields = ('email', 'first_name', 'last_name', 'phone',)
|
||||||
readonly_fields = ('last_login', 'date_joined', 'image_preview', 'cropped_image_preview', 'last_ip', 'last_country')
|
readonly_fields = ('last_login', 'date_joined', 'image_preview', 'cropped_image_preview', 'last_ip', 'last_country')
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {'fields': ('email', 'password',)}),
|
(None, {'fields': ('email', 'password',)}),
|
||||||
(_('Personal info'), {
|
(_('Personal info'), {
|
||||||
'fields': ('username', 'first_name', 'last_name',
|
'fields': ('username', 'first_name', 'last_name',
|
||||||
'image_url', 'image_preview',
|
'image_url', 'image_preview', 'phone',
|
||||||
'cropped_image_url', 'cropped_image_preview',)}),
|
'cropped_image_url', 'cropped_image_preview',)}),
|
||||||
(_('Subscription'), {
|
(_('Subscription'), {
|
||||||
'fields': (
|
'fields': (
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@ from account import models
|
||||||
class AccountBackOfficeFilter(filters.FilterSet):
|
class AccountBackOfficeFilter(filters.FilterSet):
|
||||||
"""Account filter set."""
|
"""Account filter set."""
|
||||||
|
|
||||||
|
search = filters.CharFilter(method='search_text')
|
||||||
|
role_country_code = filters.CharFilter(method='by_role_country_code')
|
||||||
role = filters.MultipleChoiceFilter(choices=models.Role.ROLE_CHOICES,
|
role = filters.MultipleChoiceFilter(choices=models.Role.ROLE_CHOICES,
|
||||||
method='filter_by_roles')
|
method='by_roles')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class."""
|
"""Meta class."""
|
||||||
|
|
@ -21,9 +23,33 @@ class AccountBackOfficeFilter(filters.FilterSet):
|
||||||
'is_staff',
|
'is_staff',
|
||||||
'is_active',
|
'is_active',
|
||||||
'is_superuser',
|
'is_superuser',
|
||||||
|
'search',
|
||||||
|
'role_country_code',
|
||||||
)
|
)
|
||||||
|
|
||||||
def filter_by_roles(self, queryset, name, value):
|
def by_roles(self, queryset, name, value):
|
||||||
if value not in EMPTY_VALUES:
|
if value not in EMPTY_VALUES:
|
||||||
return queryset.by_roles(value)
|
return queryset.by_roles(value)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
def search_text(self, queryset, name, value):
|
||||||
|
if value not in EMPTY_VALUES:
|
||||||
|
return queryset.search_text(value)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def by_role_country_code(self, queryset, name, value):
|
||||||
|
if value not in EMPTY_VALUES:
|
||||||
|
return queryset.by_role_country_code(value)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
class RoleListFilter(filters.FilterSet):
|
||||||
|
"""Role filter set."""
|
||||||
|
country_code = filters.CharFilter(field_name='country__code')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Meta class."""
|
||||||
|
model = models.Role
|
||||||
|
fields = [
|
||||||
|
'country_code',
|
||||||
|
]
|
||||||
|
|
|
||||||
19
apps/account/migrations/0033_user_phone.py
Normal file
19
apps/account/migrations/0033_user_phone.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 2.2.7 on 2020-01-20 09:39
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
import phonenumber_field.modelfields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('account', '0032_auto_20200114_1311'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='phone',
|
||||||
|
field=phonenumber_field.modelfields.PhoneNumberField(blank=True, default=None, max_length=128, null=True, verbose_name='Phone'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -20,6 +20,8 @@ from main.models import SiteSettings
|
||||||
from utils.models import GMTokenGenerator
|
from utils.models import GMTokenGenerator
|
||||||
from utils.models import ImageMixin, ProjectBaseMixin, PlatformMixin
|
from utils.models import ImageMixin, ProjectBaseMixin, PlatformMixin
|
||||||
from utils.tokens import GMRefreshToken
|
from utils.tokens import GMRefreshToken
|
||||||
|
from django.contrib.postgres.search import SearchVector
|
||||||
|
from phonenumber_field.modelfields import PhoneNumberField
|
||||||
|
|
||||||
|
|
||||||
class RoleQuerySet(models.QuerySet):
|
class RoleQuerySet(models.QuerySet):
|
||||||
|
|
@ -142,6 +144,24 @@ class UserQuerySet(models.QuerySet):
|
||||||
role = Role.objects.filter(role=Role.ESTABLISHMENT_MANAGER).first()
|
role = Role.objects.filter(role=Role.ESTABLISHMENT_MANAGER).first()
|
||||||
return self.by_role(role).filter(userrole__establishment=establishment)
|
return self.by_role(role).filter(userrole__establishment=establishment)
|
||||||
|
|
||||||
|
def annotate_search_text(self):
|
||||||
|
"""Full-text search"""
|
||||||
|
return self.annotate(search_text=SearchVector(
|
||||||
|
'username',
|
||||||
|
'first_name',
|
||||||
|
'last_name',
|
||||||
|
'email',
|
||||||
|
'phone',
|
||||||
|
))
|
||||||
|
|
||||||
|
def search_text(self, value: str):
|
||||||
|
"""Filter by annotated search vector."""
|
||||||
|
return self.annotate_search_text().filter(search_text=value)
|
||||||
|
|
||||||
|
def by_role_country_code(self, country_code: str):
|
||||||
|
"""Filter by role country code."""
|
||||||
|
return self.filter(userrole__role__country__code=country_code).distinct()
|
||||||
|
|
||||||
|
|
||||||
class User(AbstractUser):
|
class User(AbstractUser):
|
||||||
"""Base user model."""
|
"""Base user model."""
|
||||||
|
|
@ -178,6 +198,8 @@ class User(AbstractUser):
|
||||||
default=None,
|
default=None,
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
)
|
)
|
||||||
|
phone = PhoneNumberField(blank=True, null=True, default=None,
|
||||||
|
verbose_name=_('Phone'))
|
||||||
|
|
||||||
EMAIL_FIELD = 'email'
|
EMAIL_FIELD = 'email'
|
||||||
USERNAME_FIELD = 'email'
|
USERNAME_FIELD = 'email'
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from account import models
|
from account import models
|
||||||
from account.models import User
|
from account.serializers import RoleBaseSerializer, UserSerializer, subscriptions_handler
|
||||||
from account.serializers import RoleBaseSerializer, subscriptions_handler
|
|
||||||
from main.models import SiteSettings
|
from main.models import SiteSettings
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -17,20 +16,12 @@ class _SiteSettingsSerializer(serializers.ModelSerializer):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BackUserSerializer(serializers.ModelSerializer):
|
class BackUserSerializer(UserSerializer):
|
||||||
|
|
||||||
last_country = _SiteSettingsSerializer(read_only=True)
|
last_country = _SiteSettingsSerializer(read_only=True)
|
||||||
roles = RoleBaseSerializer(many=True, read_only=True)
|
roles = RoleBaseSerializer(many=True, read_only=True)
|
||||||
subscriptions = serializers.ListField(
|
|
||||||
source='subscription_types',
|
|
||||||
allow_null=True,
|
|
||||||
allow_empty=True,
|
|
||||||
child=serializers.IntegerField(min_value=1),
|
|
||||||
required=False,
|
|
||||||
help_text='list of subscription_types id',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta(UserSerializer.Meta):
|
||||||
model = User
|
|
||||||
fields = (
|
fields = (
|
||||||
'id',
|
'id',
|
||||||
'last_login',
|
'last_login',
|
||||||
|
|
@ -54,9 +45,12 @@ class BackUserSerializer(serializers.ModelSerializer):
|
||||||
'last_country',
|
'last_country',
|
||||||
'roles',
|
'roles',
|
||||||
'subscriptions',
|
'subscriptions',
|
||||||
|
'phone',
|
||||||
|
'phone_as_international',
|
||||||
)
|
)
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'password': {'write_only': True},
|
'password': {'write_only': True},
|
||||||
|
'phone': {'write_only': True},
|
||||||
}
|
}
|
||||||
read_only_fields = (
|
read_only_fields = (
|
||||||
'old_password',
|
'old_password',
|
||||||
|
|
@ -82,8 +76,7 @@ class BackUserSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
|
||||||
class BackDetailUserSerializer(BackUserSerializer):
|
class BackDetailUserSerializer(BackUserSerializer):
|
||||||
class Meta:
|
class Meta(BackUserSerializer.Meta):
|
||||||
model = User
|
|
||||||
fields = (
|
fields = (
|
||||||
'id',
|
'id',
|
||||||
'last_country',
|
'last_country',
|
||||||
|
|
@ -109,6 +102,8 @@ class BackDetailUserSerializer(BackUserSerializer):
|
||||||
'groups',
|
'groups',
|
||||||
'user_permissions',
|
'user_permissions',
|
||||||
'subscriptions',
|
'subscriptions',
|
||||||
|
'phone',
|
||||||
|
'phone_as_international',
|
||||||
)
|
)
|
||||||
read_only_fields = (
|
read_only_fields = (
|
||||||
'old_password',
|
'old_password',
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ from notification.models import Subscribe, Subscriber
|
||||||
from utils import exceptions as utils_exceptions
|
from utils import exceptions as utils_exceptions
|
||||||
from utils import methods as utils_methods
|
from utils import methods as utils_methods
|
||||||
from utils.methods import generate_string_code
|
from utils.methods import generate_string_code
|
||||||
|
from phonenumber_field.serializerfields import PhoneNumberField
|
||||||
|
|
||||||
|
|
||||||
def subscriptions_handler(subscriptions_list, user):
|
def subscriptions_handler(subscriptions_list, user):
|
||||||
|
|
@ -43,6 +44,7 @@ class RoleBaseSerializer(serializers.ModelSerializer):
|
||||||
"""Serializer for model Role."""
|
"""Serializer for model Role."""
|
||||||
role_display = serializers.CharField(source='get_role_display', read_only=True)
|
role_display = serializers.CharField(source='get_role_display', read_only=True)
|
||||||
navigation_bar_permission = NavigationBarPermissionBaseSerializer(read_only=True)
|
navigation_bar_permission = NavigationBarPermissionBaseSerializer(read_only=True)
|
||||||
|
country_code = serializers.CharField(source='country.code', read_only=True, allow_null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class."""
|
"""Meta class."""
|
||||||
|
|
@ -51,6 +53,7 @@ class RoleBaseSerializer(serializers.ModelSerializer):
|
||||||
'id',
|
'id',
|
||||||
'role_display',
|
'role_display',
|
||||||
'navigation_bar_permission',
|
'navigation_bar_permission',
|
||||||
|
'country_code',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -75,6 +78,9 @@ class UserSerializer(serializers.ModelSerializer):
|
||||||
required=False,
|
required=False,
|
||||||
help_text='list of subscription_types id',
|
help_text='list of subscription_types id',
|
||||||
)
|
)
|
||||||
|
phone_as_international = PhoneNumberField(source='phone.as_international',
|
||||||
|
allow_null=True,
|
||||||
|
read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.User
|
model = models.User
|
||||||
|
|
@ -90,6 +96,8 @@ class UserSerializer(serializers.ModelSerializer):
|
||||||
'newsletter',
|
'newsletter',
|
||||||
'roles',
|
'roles',
|
||||||
'subscriptions',
|
'subscriptions',
|
||||||
|
'phone',
|
||||||
|
'phone_as_international',
|
||||||
]
|
]
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'first_name': {'required': False, 'write_only': True, },
|
'first_name': {'required': False, 'write_only': True, },
|
||||||
|
|
@ -98,6 +106,7 @@ class UserSerializer(serializers.ModelSerializer):
|
||||||
'image_url': {'required': False, },
|
'image_url': {'required': False, },
|
||||||
'cropped_image_url': {'required': False, },
|
'cropped_image_url': {'required': False, },
|
||||||
'newsletter': {'required': False, },
|
'newsletter': {'required': False, },
|
||||||
|
'phone': {'required': False, 'write_only': True, }
|
||||||
}
|
}
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
|
|
@ -113,7 +122,7 @@ class UserSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
def validate_email(self, value):
|
def validate_email(self, value):
|
||||||
"""Validate email value"""
|
"""Validate email value"""
|
||||||
if value == self.instance.email:
|
if hasattr(self.instance, 'email') and self.instance.email and value == self.instance.email:
|
||||||
raise serializers.ValidationError(detail='Equal email address.')
|
raise serializers.ValidationError(detail='Equal email address.')
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ from account.serializers.common import RoleBaseSerializer
|
||||||
class RoleListView(generics.ListCreateAPIView):
|
class RoleListView(generics.ListCreateAPIView):
|
||||||
serializer_class = RoleBaseSerializer
|
serializer_class = RoleBaseSerializer
|
||||||
queryset = models.Role.objects.all()
|
queryset = models.Role.objects.all()
|
||||||
|
filter_class = filters.RoleListFilter
|
||||||
|
|
||||||
|
|
||||||
class RoleTabRetrieveView(generics.GenericAPIView):
|
class RoleTabRetrieveView(generics.GenericAPIView):
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,3 @@ class Image(ProjectBaseMixin, SORLImageMixin, PlatformMixin):
|
||||||
if completely:
|
if completely:
|
||||||
# Delete an instance of image
|
# Delete an instance of image
|
||||||
super().delete()
|
super().delete()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ from timetable.models import Timetable
|
||||||
from utils.legacy_parser import parse_legacy_schedule_content
|
from utils.legacy_parser import parse_legacy_schedule_content
|
||||||
from utils.serializers import TimeZoneChoiceField
|
from utils.serializers import TimeZoneChoiceField
|
||||||
from utils.slug_generator import generate_unique_slug
|
from utils.slug_generator import generate_unique_slug
|
||||||
|
from phonenumber_field.phonenumber import PhoneNumber
|
||||||
|
|
||||||
|
|
||||||
class EstablishmentSerializer(serializers.ModelSerializer):
|
class EstablishmentSerializer(serializers.ModelSerializer):
|
||||||
|
|
@ -58,6 +59,7 @@ class EstablishmentSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
old_type = data.pop('type', None)
|
old_type = data.pop('type', None)
|
||||||
|
phone = data.pop('phone', None)
|
||||||
|
|
||||||
data.update({
|
data.update({
|
||||||
'slug': generate_unique_slug(Establishment, data['slug'] if data['slug'] else data['name']),
|
'slug': generate_unique_slug(Establishment, data['slug'] if data['slug'] else data['name']),
|
||||||
|
|
@ -65,6 +67,7 @@ class EstablishmentSerializer(serializers.ModelSerializer):
|
||||||
'establishment_type_id': self.get_type(old_type),
|
'establishment_type_id': self.get_type(old_type),
|
||||||
'is_publish': data.get('state') == 'published',
|
'is_publish': data.get('state') == 'published',
|
||||||
'subtype': self.get_subtype(old_type),
|
'subtype': self.get_subtype(old_type),
|
||||||
|
'phone': self.get_phone(phone),
|
||||||
})
|
})
|
||||||
data.pop('location')
|
data.pop('location')
|
||||||
data.pop('state')
|
data.pop('state')
|
||||||
|
|
@ -179,6 +182,13 @@ class EstablishmentSerializer(serializers.ModelSerializer):
|
||||||
establishment_type_id=establishment_type_id)
|
establishment_type_id=establishment_type_id)
|
||||||
return subtype
|
return subtype
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_phone(phone: str):
|
||||||
|
phone_obj = PhoneNumber.from_string(phone_number=phone, region='FR')
|
||||||
|
if phone_obj.is_valid():
|
||||||
|
fmt = PhoneNumber.format_map[getattr(settings, 'PHONENUMBER_DB_FORMAT', 'INTERNATIONAL')]
|
||||||
|
return phone_obj.format_as(fmt)
|
||||||
|
|
||||||
|
|
||||||
class EstablishmentNoteSerializer(serializers.ModelSerializer):
|
class EstablishmentNoteSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -517,7 +517,7 @@ STATICFILES_DIRS = (
|
||||||
# MEDIA
|
# MEDIA
|
||||||
MEDIA_LOCATION = 'media'
|
MEDIA_LOCATION = 'media'
|
||||||
|
|
||||||
PHONENUMBER_DB_FORMAT = 'NATIONAL'
|
PHONENUMBER_DB_FORMAT = 'INTERNATIONAL'
|
||||||
PHONENUMBER_DEFAULT_REGION = "FR"
|
PHONENUMBER_DEFAULT_REGION = "FR"
|
||||||
|
|
||||||
FALLBACK_LOCALE = 'en-GB'
|
FALLBACK_LOCALE = 'en-GB'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user