205 lines
6.7 KiB
Python
205 lines
6.7 KiB
Python
from rest_framework import serializers
|
|
from django.contrib.auth import authenticate
|
|
from django.contrib.auth.password_validation import validate_password
|
|
from django.core.exceptions import ValidationError
|
|
from .models import User, UserProfile, LoginAttempt, EmailVerification
|
|
import uuid
|
|
from datetime import timedelta
|
|
from django.utils import timezone
|
|
|
|
|
|
class UserRegistrationSerializer(serializers.ModelSerializer):
|
|
"""Serializer for user registration."""
|
|
|
|
password = serializers.CharField(write_only=True, validators=[validate_password])
|
|
password_confirm = serializers.CharField(write_only=True)
|
|
|
|
class Meta:
|
|
model = User
|
|
fields = ('email', 'username', 'first_name', 'last_name', 'password', 'password_confirm')
|
|
extra_kwargs = {
|
|
'email': {'required': True},
|
|
'username': {'required': True},
|
|
'first_name': {'required': True},
|
|
'last_name': {'required': True},
|
|
}
|
|
|
|
def validate(self, attrs):
|
|
if attrs['password'] != attrs['password_confirm']:
|
|
raise serializers.ValidationError("Passwords don't match.")
|
|
return attrs
|
|
|
|
def validate_email(self, value):
|
|
if User.objects.filter(email=value).exists():
|
|
raise serializers.ValidationError("A user with this email already exists.")
|
|
return value
|
|
|
|
def validate_username(self, value):
|
|
if User.objects.filter(username=value).exists():
|
|
raise serializers.ValidationError("A user with this username already exists.")
|
|
return value
|
|
|
|
def create(self, validated_data):
|
|
validated_data.pop('password_confirm')
|
|
user = User.objects.create_user(**validated_data)
|
|
|
|
# Create user profile
|
|
UserProfile.objects.create(user=user)
|
|
|
|
# Create email verification token
|
|
token = str(uuid.uuid4())
|
|
EmailVerification.objects.create(
|
|
user=user,
|
|
token=token,
|
|
expires_at=timezone.now() + timedelta(hours=24)
|
|
)
|
|
|
|
return user
|
|
|
|
|
|
class UserLoginSerializer(serializers.Serializer):
|
|
"""Serializer for user login."""
|
|
|
|
email = serializers.EmailField()
|
|
password = serializers.CharField()
|
|
|
|
def validate(self, attrs):
|
|
email = attrs.get('email')
|
|
password = attrs.get('password')
|
|
|
|
if email and password:
|
|
user = authenticate(username=email, password=password)
|
|
if not user:
|
|
raise serializers.ValidationError('Invalid email or password.')
|
|
if not user.is_active:
|
|
raise serializers.ValidationError('User account is disabled.')
|
|
attrs['user'] = user
|
|
else:
|
|
raise serializers.ValidationError('Must include email and password.')
|
|
|
|
return attrs
|
|
|
|
|
|
class UserSerializer(serializers.ModelSerializer):
|
|
"""Serializer for user data."""
|
|
|
|
full_name = serializers.CharField(source='get_full_name', read_only=True)
|
|
profile = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = User
|
|
fields = (
|
|
'id', 'email', 'username', 'first_name', 'last_name', 'full_name',
|
|
'avatar', 'is_verified', 'created_at', 'updated_at', 'profile'
|
|
)
|
|
read_only_fields = ('id', 'created_at', 'updated_at', 'is_verified')
|
|
|
|
def get_profile(self, obj):
|
|
try:
|
|
profile = obj.profile
|
|
return UserProfileSerializer(profile).data
|
|
except UserProfile.DoesNotExist:
|
|
return None
|
|
|
|
|
|
class UserProfileSerializer(serializers.ModelSerializer):
|
|
"""Serializer for user profile."""
|
|
|
|
class Meta:
|
|
model = UserProfile
|
|
fields = '__all__'
|
|
read_only_fields = ('user', 'created_at', 'updated_at')
|
|
|
|
|
|
class EmailSettingsSerializer(serializers.ModelSerializer):
|
|
"""Serializer for email server settings."""
|
|
|
|
smtp_password = serializers.CharField(write_only=True, required=False)
|
|
imap_password = serializers.CharField(write_only=True, required=False)
|
|
|
|
class Meta:
|
|
model = User
|
|
fields = (
|
|
'smtp_host', 'smtp_port', 'smtp_username', 'smtp_password',
|
|
'smtp_use_tls', 'imap_host', 'imap_port', 'imap_username',
|
|
'imap_password', 'imap_use_ssl'
|
|
)
|
|
|
|
def update(self, instance, validated_data):
|
|
smtp_password = validated_data.pop('smtp_password', None)
|
|
imap_password = validated_data.pop('imap_password', None)
|
|
|
|
if smtp_password:
|
|
instance.set_smtp_password(smtp_password)
|
|
|
|
if imap_password:
|
|
instance.set_imap_password(imap_password)
|
|
|
|
for attr, value in validated_data.items():
|
|
setattr(instance, attr, value)
|
|
|
|
instance.save()
|
|
return instance
|
|
|
|
|
|
class PasswordChangeSerializer(serializers.Serializer):
|
|
"""Serializer for password change."""
|
|
|
|
old_password = serializers.CharField()
|
|
new_password = serializers.CharField(validators=[validate_password])
|
|
new_password_confirm = serializers.CharField()
|
|
|
|
def validate_old_password(self, value):
|
|
user = self.context['request'].user
|
|
if not user.check_password(value):
|
|
raise serializers.ValidationError('Old password is incorrect.')
|
|
return value
|
|
|
|
def validate(self, attrs):
|
|
if attrs['new_password'] != attrs['new_password_confirm']:
|
|
raise serializers.ValidationError("New passwords don't match.")
|
|
return attrs
|
|
|
|
def save(self):
|
|
user = self.context['request'].user
|
|
user.set_password(self.validated_data['new_password'])
|
|
user.save()
|
|
return user
|
|
|
|
|
|
class EmailVerificationSerializer(serializers.Serializer):
|
|
"""Serializer for email verification."""
|
|
|
|
token = serializers.CharField()
|
|
|
|
def validate_token(self, value):
|
|
try:
|
|
verification = EmailVerification.objects.get(token=value)
|
|
if verification.is_used:
|
|
raise serializers.ValidationError('Verification token has already been used.')
|
|
if verification.is_expired():
|
|
raise serializers.ValidationError('Verification token has expired.')
|
|
return verification
|
|
except EmailVerification.DoesNotExist:
|
|
raise serializers.ValidationError('Invalid verification token.')
|
|
|
|
def save(self):
|
|
verification = self.validated_data['token']
|
|
verification.is_used = True
|
|
verification.save()
|
|
|
|
user = verification.user
|
|
user.is_verified = True
|
|
user.save()
|
|
|
|
return user
|
|
|
|
|
|
class LoginAttemptSerializer(serializers.ModelSerializer):
|
|
"""Serializer for login attempts."""
|
|
|
|
class Meta:
|
|
model = LoginAttempt
|
|
fields = '__all__'
|
|
read_only_fields = ('timestamp',)
|