""" 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