2025-08-12 13:33:25 +03:00

218 lines
7.5 KiB
Python

"""
Accounts API serializers.
"""
from rest_framework import serializers
from django.contrib.auth import authenticate
from ..models import User, TwoFactorDevice, SocialAccount, UserSession, PasswordHistory
class UserSerializer(serializers.ModelSerializer):
"""
User serializer.
"""
tenant_name = serializers.CharField(source='tenant.name', read_only=True)
full_name = serializers.CharField(source='get_full_name', read_only=True)
display_name = serializers.CharField(source='get_display_name', read_only=True)
is_account_locked = serializers.ReadOnlyField()
is_password_expired = serializers.ReadOnlyField()
is_license_expired = serializers.ReadOnlyField()
class Meta:
model = User
fields = [
'id', 'user_id', 'username', 'email', 'first_name', 'last_name',
'middle_name', 'preferred_name', 'full_name', 'display_name',
'phone_number', 'mobile_number', 'tenant', 'tenant_name',
'employee_id', 'department', 'job_title', 'role',
'license_number', 'license_state', 'license_expiry',
'dea_number', 'npi_number', 'timezone', 'language', 'theme',
'profile_picture', 'bio', 'is_active', 'is_verified', 'is_approved',
'approval_date', 'two_factor_enabled', 'max_concurrent_sessions',
'session_timeout_minutes', 'is_account_locked', 'is_password_expired',
'is_license_expired', 'last_login', 'date_joined', 'created_at', 'updated_at'
]
read_only_fields = [
'user_id', 'last_login', 'date_joined', 'created_at', 'updated_at'
]
extra_kwargs = {
'password': {'write_only': True}
}
def create(self, validated_data):
password = validated_data.pop('password', None)
user = User.objects.create_user(**validated_data)
if password:
user.set_password(password)
user.save()
return user
def update(self, instance, validated_data):
password = validated_data.pop('password', None)
user = super().update(instance, validated_data)
if password:
user.set_password(password)
user.save()
return user
class UserProfileSerializer(serializers.ModelSerializer):
"""
User profile serializer for self-service updates.
"""
tenant_name = serializers.CharField(source='tenant.name', read_only=True)
full_name = serializers.CharField(source='get_full_name', read_only=True)
class Meta:
model = User
fields = [
'id', 'username', 'email', 'first_name', 'last_name',
'middle_name', 'preferred_name', 'full_name',
'phone_number', 'mobile_number', 'tenant_name',
'timezone', 'language', 'theme', 'profile_picture', 'bio'
]
read_only_fields = ['id', 'username', 'tenant_name']
class TwoFactorDeviceSerializer(serializers.ModelSerializer):
"""
Two-factor device serializer.
"""
user_name = serializers.CharField(source='user.get_display_name', read_only=True)
class Meta:
model = TwoFactorDevice
fields = [
'device_id', 'user', 'user_name', 'name', 'device_type',
'phone_number', 'email_address', 'is_active', 'is_verified',
'verified_at', 'last_used_at', 'usage_count',
'created_at', 'updated_at'
]
read_only_fields = ['device_id', 'created_at', 'updated_at']
extra_kwargs = {
'secret_key': {'write_only': True}
}
class SocialAccountSerializer(serializers.ModelSerializer):
"""
Social account serializer.
"""
user_name = serializers.CharField(source='user.get_display_name', read_only=True)
class Meta:
model = SocialAccount
fields = [
'id', 'user', 'user_name', 'provider', 'provider_id',
'provider_email', 'display_name', 'profile_url', 'avatar_url',
'is_active', 'created_at', 'updated_at', 'last_login_at'
]
read_only_fields = ['created_at', 'updated_at']
extra_kwargs = {
'access_token': {'write_only': True},
'refresh_token': {'write_only': True}
}
class UserSessionSerializer(serializers.ModelSerializer):
"""
User session serializer.
"""
user_name = serializers.CharField(source='user.get_display_name', read_only=True)
is_expired = serializers.ReadOnlyField()
class Meta:
model = UserSession
fields = [
'session_id', 'user', 'user_name', 'session_key',
'ip_address', 'user_agent', 'device_type', 'browser',
'operating_system', 'country', 'region', 'city',
'is_active', 'login_method', 'is_expired',
'created_at', 'last_activity_at', 'expires_at', 'ended_at'
]
read_only_fields = ['session_id', 'created_at', 'last_activity_at']
class PasswordHistorySerializer(serializers.ModelSerializer):
"""
Password history serializer.
"""
user_name = serializers.CharField(source='user.get_display_name', read_only=True)
class Meta:
model = PasswordHistory
fields = ['id', 'user', 'user_name', 'created_at']
read_only_fields = ['created_at']
extra_kwargs = {
'password_hash': {'write_only': True}
}
class LoginSerializer(serializers.Serializer):
"""
Login serializer.
"""
username = serializers.CharField()
password = serializers.CharField(write_only=True)
remember_me = serializers.BooleanField(default=False)
def validate(self, attrs):
username = attrs.get('username')
password = attrs.get('password')
if username and password:
user = authenticate(username=username, password=password)
if not user:
raise serializers.ValidationError('Invalid credentials')
if not user.is_active:
raise serializers.ValidationError('User account is disabled')
if user.is_account_locked:
raise serializers.ValidationError('User account is locked')
attrs['user'] = user
else:
raise serializers.ValidationError('Must include username and password')
return attrs
class PasswordChangeSerializer(serializers.Serializer):
"""
Password change serializer.
"""
old_password = serializers.CharField(write_only=True)
new_password = serializers.CharField(write_only=True)
confirm_password = serializers.CharField(write_only=True)
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['confirm_password']:
raise serializers.ValidationError('New passwords do not match')
return attrs
def save(self):
user = self.context['request'].user
user.set_password(self.validated_data['new_password'])
user.save()
return user
class PasswordResetSerializer(serializers.Serializer):
"""
Password reset serializer.
"""
email = serializers.EmailField()
def validate_email(self, value):
try:
user = User.objects.get(email=value, is_active=True)
except User.DoesNotExist:
raise serializers.ValidationError('No active user found with this email')
return value