265 lines
9.2 KiB
Python
265 lines
9.2 KiB
Python
"""
|
|
Accounts serializers
|
|
"""
|
|
from django.contrib.auth import get_user_model
|
|
from rest_framework import serializers
|
|
|
|
from .models import (
|
|
AcknowledgementChecklistItem,
|
|
AcknowledgementContent,
|
|
Role,
|
|
UserAcknowledgement,
|
|
)
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
class UserSerializer(serializers.ModelSerializer):
|
|
"""User serializer"""
|
|
roles = serializers.SerializerMethodField()
|
|
hospital_name = serializers.CharField(source='hospital.name', read_only=True)
|
|
department_name = serializers.CharField(source='department.name', read_only=True)
|
|
|
|
class Meta:
|
|
model = User
|
|
fields = [
|
|
'id', 'username', 'email', 'first_name', 'last_name',
|
|
'phone', 'employee_id', 'hospital', 'hospital_name',
|
|
'department', 'department_name', 'avatar', 'bio',
|
|
'language', 'is_active', 'roles', 'date_joined',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['id', 'date_joined', 'created_at', 'updated_at']
|
|
|
|
def get_roles(self, obj):
|
|
"""Get user roles"""
|
|
return obj.get_role_names()
|
|
|
|
|
|
class UserCreateSerializer(serializers.ModelSerializer):
|
|
"""User creation serializer with password"""
|
|
password = serializers.CharField(write_only=True, required=True, style={'input_type': 'password'})
|
|
password_confirm = serializers.CharField(write_only=True, required=True, style={'input_type': 'password'})
|
|
|
|
class Meta:
|
|
model = User
|
|
fields = [
|
|
'username', 'email', 'password', 'password_confirm',
|
|
'first_name', 'last_name', 'phone', 'employee_id',
|
|
'hospital', 'department', 'language'
|
|
]
|
|
|
|
def validate(self, attrs):
|
|
"""Validate passwords match"""
|
|
if attrs['password'] != attrs['password_confirm']:
|
|
raise serializers.ValidationError({"password": "Passwords do not match."})
|
|
return attrs
|
|
|
|
def create(self, validated_data):
|
|
"""Create user with hashed password"""
|
|
validated_data.pop('password_confirm')
|
|
password = validated_data.pop('password')
|
|
user = User.objects.create(**validated_data)
|
|
user.set_password(password)
|
|
user.save()
|
|
return user
|
|
|
|
|
|
class UserUpdateSerializer(serializers.ModelSerializer):
|
|
"""User update serializer (without password)"""
|
|
|
|
class Meta:
|
|
model = User
|
|
fields = [
|
|
'first_name', 'last_name', 'phone', 'employee_id',
|
|
'hospital', 'department', 'avatar', 'bio', 'language', 'is_active'
|
|
]
|
|
|
|
|
|
class ChangePasswordSerializer(serializers.Serializer):
|
|
"""Change password serializer"""
|
|
old_password = serializers.CharField(required=True, write_only=True)
|
|
new_password = serializers.CharField(required=True, write_only=True)
|
|
new_password_confirm = serializers.CharField(required=True, write_only=True)
|
|
|
|
def validate(self, attrs):
|
|
"""Validate passwords"""
|
|
if attrs['new_password'] != attrs['new_password_confirm']:
|
|
raise serializers.ValidationError({"new_password": "Passwords do not match."})
|
|
return attrs
|
|
|
|
def validate_old_password(self, value):
|
|
"""Validate old password"""
|
|
user = self.context['request'].user
|
|
if not user.check_password(value):
|
|
raise serializers.ValidationError("Old password is incorrect.")
|
|
return value
|
|
|
|
|
|
class RoleSerializer(serializers.ModelSerializer):
|
|
"""Role serializer"""
|
|
group_name = serializers.CharField(source='group.name', read_only=True)
|
|
|
|
class Meta:
|
|
model = Role
|
|
fields = [
|
|
'id', 'name', 'display_name', 'description',
|
|
'group', 'group_name', 'level', 'permissions',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
|
|
|
|
# ==================== Onboarding Serializers ====================
|
|
|
|
class ProvisionalUserSerializer(serializers.ModelSerializer):
|
|
"""Serializer for creating provisional users"""
|
|
roles = serializers.ListField(
|
|
child=serializers.CharField(),
|
|
write_only=True,
|
|
required=False,
|
|
default=list,
|
|
help_text="List of role names to assign"
|
|
)
|
|
|
|
class Meta:
|
|
model = User
|
|
fields = [
|
|
'email', 'first_name', 'last_name', 'phone',
|
|
'employee_id', 'hospital', 'department',
|
|
'language', 'roles'
|
|
]
|
|
|
|
def create(self, validated_data):
|
|
"""Create provisional user"""
|
|
roles = validated_data.pop('roles', [])
|
|
user = User(**validated_data)
|
|
user.is_provisional = True
|
|
user.set_unusable_password()
|
|
user.save()
|
|
|
|
# Assign roles
|
|
for role_name in roles:
|
|
from .models import Role as RoleModel
|
|
try:
|
|
role = RoleModel.objects.get(name=role_name)
|
|
user.groups.add(role.group)
|
|
except RoleModel.DoesNotExist:
|
|
pass
|
|
|
|
return user
|
|
|
|
|
|
class AcknowledgementContentSerializer(serializers.ModelSerializer):
|
|
"""Serializer for acknowledgement content"""
|
|
role_display = serializers.CharField(source='get_role_display', read_only=True)
|
|
|
|
class Meta:
|
|
model = AcknowledgementContent
|
|
fields = [
|
|
'id', 'role', 'role_display', 'code',
|
|
'title_en', 'title_ar', 'description_en', 'description_ar',
|
|
'content_en', 'content_ar', 'icon', 'color',
|
|
'order', 'is_active', 'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
|
|
|
|
class AcknowledgementChecklistItemSerializer(serializers.ModelSerializer):
|
|
"""Serializer for checklist items"""
|
|
role_display = serializers.CharField(source='get_role_display', read_only=True)
|
|
content_title_en = serializers.CharField(source='content.title_en', read_only=True)
|
|
content_title_ar = serializers.CharField(source='content.title_ar', read_only=True)
|
|
|
|
class Meta:
|
|
model = AcknowledgementChecklistItem
|
|
fields = [
|
|
'id', 'role', 'role_display', 'content',
|
|
'content_title_en', 'content_title_ar',
|
|
'code', 'text_en', 'text_ar',
|
|
'description_en', 'description_ar',
|
|
'is_required', 'order', 'is_active',
|
|
'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = ['id', 'created_at', 'updated_at']
|
|
|
|
|
|
class UserAcknowledgementSerializer(serializers.ModelSerializer):
|
|
"""Serializer for user acknowledgements"""
|
|
user_email = serializers.CharField(source='user.email', read_only=True)
|
|
user_name = serializers.CharField(source='user.get_full_name', read_only=True)
|
|
checklist_item_text_en = serializers.CharField(source='checklist_item.text_en', read_only=True)
|
|
checklist_item_text_ar = serializers.CharField(source='checklist_item.text_ar', read_only=True)
|
|
checklist_item_code = serializers.CharField(source='checklist_item.code', read_only=True)
|
|
|
|
class Meta:
|
|
model = UserAcknowledgement
|
|
fields = [
|
|
'id', 'user', 'user_email', 'user_name',
|
|
'checklist_item', 'checklist_item_text_en',
|
|
'checklist_item_text_ar', 'checklist_item_code',
|
|
'is_acknowledged', 'acknowledged_at',
|
|
'signature', 'signature_ip', 'signature_user_agent',
|
|
'metadata', 'created_at', 'updated_at'
|
|
]
|
|
read_only_fields = [
|
|
'id', 'user', 'acknowledged_at',
|
|
'created_at', 'updated_at'
|
|
]
|
|
|
|
|
|
class WizardProgressSerializer(serializers.Serializer):
|
|
"""Serializer for wizard progress"""
|
|
current_step = serializers.IntegerField()
|
|
completed_steps = serializers.ListField(child=serializers.IntegerField())
|
|
progress_percentage = serializers.FloatField()
|
|
total_required_items = serializers.IntegerField()
|
|
acknowledged_items = serializers.IntegerField()
|
|
|
|
|
|
class AcknowledgeItemSerializer(serializers.Serializer):
|
|
"""Serializer for acknowledging checklist items"""
|
|
checklist_item_id = serializers.UUIDField(required=True)
|
|
signature = serializers.CharField(required=False, allow_blank=True)
|
|
|
|
|
|
class AccountActivationSerializer(serializers.Serializer):
|
|
"""Serializer for account activation"""
|
|
username = serializers.CharField(
|
|
required=True,
|
|
min_length=3,
|
|
max_length=150,
|
|
help_text="Desired username"
|
|
)
|
|
password = serializers.CharField(
|
|
required=True,
|
|
min_length=8,
|
|
write_only=True,
|
|
style={'input_type': 'password'}
|
|
)
|
|
password_confirm = serializers.CharField(
|
|
required=True,
|
|
write_only=True,
|
|
style={'input_type': 'password'}
|
|
)
|
|
signature = serializers.CharField(
|
|
required=True,
|
|
help_text="Digital signature data (base64 encoded)"
|
|
)
|
|
|
|
def validate(self, attrs):
|
|
"""Validate passwords match"""
|
|
if attrs['password'] != attrs['password_confirm']:
|
|
raise serializers.ValidationError({"password": "Passwords do not match."})
|
|
|
|
# Check if username is available
|
|
if User.objects.filter(username=attrs['username']).exists():
|
|
raise serializers.ValidationError({"username": "Username already taken."})
|
|
|
|
return attrs
|
|
|
|
|
|
class ResendInvitationSerializer(serializers.Serializer):
|
|
"""Serializer for resending invitation"""
|
|
user_id = serializers.UUIDField(required=True)
|