gault-millau/apps/account/serializers/common.py
2019-10-10 17:42:29 +03:00

220 lines
7.4 KiB
Python

"""Common account serializers"""
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from django.contrib.auth import password_validation as password_validators
from fcm_django.models import FCMDevice
from rest_framework import exceptions
from rest_framework import serializers
from rest_framework import validators as rest_validators
from account import models, tasks
from utils import exceptions as utils_exceptions
from utils import methods as utils_methods
# User serializers
class UserSerializer(serializers.ModelSerializer):
"""User serializer."""
# RESPONSE
email_confirmed = serializers.BooleanField(read_only=True)
fullname = serializers.CharField(source='get_full_name', read_only=True)
# REQUEST
username = serializers.CharField(
validators=(rest_validators.UniqueValidator(queryset=models.User.objects.all()),),
required=False)
first_name = serializers.CharField(required=False, write_only=True)
last_name = serializers.CharField(required=False, write_only=True)
image_url = serializers.URLField(required=False)
cropped_image_url = serializers.URLField(required=False)
email = serializers.EmailField(
validators=(rest_validators.UniqueValidator(queryset=models.User.objects.all()),),
required=False)
newsletter = serializers.BooleanField(required=False)
class Meta:
model = models.User
fields = [
'username',
'first_name',
'last_name',
'fullname',
'cropped_image_url',
'image_url',
'email',
'email_confirmed',
'newsletter',
]
def validate_email(self, value):
"""Validate email value"""
if value == self.instance.email:
raise serializers.ValidationError(detail='Equal email address.')
return value
def validate_username(self, value):
"""Custom username validation"""
valid = utils_methods.username_validator(username=value)
if not valid:
raise utils_exceptions.NotValidUsernameError()
return value
def update(self, instance, validated_data):
"""Override update method"""
old_email = instance.email
instance = super().update(instance, validated_data)
if 'email' in validated_data:
instance.email_confirmed = False
instance.email = old_email
instance.unconfirmed_email = validated_data['email']
instance.save()
# Send verification link on user email for change email address
if settings.USE_CELERY:
tasks.change_email_address.delay(
user_id=instance.id,
country_code=self.context.get('request').country_code)
else:
tasks.change_email_address(
user_id=instance.id,
country_code=self.context.get('request').country_code)
return instance
class UserBaseSerializer(serializers.ModelSerializer):
"""Serializer is used to display brief information about the user."""
fullname = serializers.CharField(source='get_full_name', read_only=True)
class Meta:
"""Meta class."""
model = models.User
fields = (
'fullname',
'cropped_image_url',
'image_url',
)
read_only_fields = fields
class ChangePasswordSerializer(serializers.ModelSerializer):
"""Serializer for model User."""
password = serializers.CharField(write_only=True)
old_password = serializers.CharField(write_only=True)
class Meta:
"""Meta class"""
model = models.User
fields = (
'password',
'old_password',
)
def validate(self, attrs):
"""Override validate method"""
password = attrs.get('password')
old_password = attrs.get('old_password')
try:
# Check old password
if not self.instance.check_password(raw_password=old_password):
raise serializers.ValidationError(_('Old password mismatch.'))
# Compare new password with the old ones
if self.instance.check_password(raw_password=password):
raise serializers.ValidationError(_('Password is already in use'))
# Validate password
password_validators.validate_password(password=password)
except serializers.ValidationError as e:
raise serializers.ValidationError({'detail': e.detail})
else:
return attrs
def update(self, instance, validated_data):
"""Override update method"""
# Update user password from instance
instance.set_password(validated_data.get('password'))
instance.save()
return instance
class ChangeEmailSerializer(serializers.ModelSerializer):
"""Change user email serializer"""
class Meta:
"""Meta class"""
model = models.User
fields = (
'email',
)
def validate_email(self, value):
"""Validate email value"""
if value == self.instance.email:
raise serializers.ValidationError()
return value
def validate(self, attrs):
"""Override validate method"""
email_confirmed = self.instance.email_confirmed
if not email_confirmed:
raise serializers.ValidationError()
return attrs
def update(self, instance, validated_data):
"""
Override update method
"""
instance.email = validated_data.get('email')
instance.email_confirmed = False
instance.save()
# Send verification link on user email for change email address
if settings.USE_CELERY:
tasks.confirm_new_email_address.delay(instance.id)
else:
tasks.confirm_new_email_address(instance.id)
return instance
# Firebase Cloud Messaging serializers
class FCMDeviceSerializer(serializers.ModelSerializer):
"""FCM Device model serializer"""
class Meta:
model = FCMDevice
fields = ('id', 'name', 'registration_id', 'device_id',
'active', 'date_created', 'type')
read_only_fields = ('id', 'date_created',)
extra_kwargs = {'active': {'default': True}}
def validate(self, attrs):
regid = attrs.get('registration_id')
dtype = attrs.get('type')
if regid and dtype and self.Meta.model.objects.filter(
registration_id=regid).exclude(type=dtype).count():
raise exceptions.ValidationError(
{'registration_id': 'This field must be unique.'})
return attrs
def __init__(self, *args, **kwargs):
super(FCMDeviceSerializer, self).__init__(*args, **kwargs)
self.fields['type'].help_text = (
'Should be one of ["%s"]' %
'", "'.join([i for i in self.fields['type'].choices]))
def create(self, validated_data):
user = self.context['request'].user
if not user.is_anonymous:
validated_data['user'] = user
device = FCMDevice.objects.create(**validated_data)
return device
def update(self, instance, validated_data):
user = self.context['request'].user
if not user.is_anonymous:
instance.user = user
instance.save()
else:
instance.user = None
instance.save()
return instance