HH/apps/accounts/serializers.py
2026-04-08 17:13:35 +03:00

373 lines
11 KiB
Python

"""
Accounts serializers
"""
from django.contrib.auth import get_user_model
from rest_framework import serializers
from .models import (
AcknowledgementCategory,
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 AcknowledgementCategorySerializer(serializers.ModelSerializer):
item_count = serializers.SerializerMethodField()
class Meta:
model = AcknowledgementCategory
fields = [
"id",
"name_en",
"name_ar",
"code",
"description",
"icon",
"color",
"order",
"is_active",
"is_default",
"item_count",
"created_at",
"updated_at",
]
read_only_fields = ["id", "created_at", "updated_at"]
def get_item_count(self, obj):
return obj.checklist_items.filter(is_active=True).count()
class AcknowledgementContentSerializer(serializers.ModelSerializer):
category_name_en = serializers.CharField(source="category.name_en", read_only=True)
category_name_ar = serializers.CharField(source="category.name_ar", read_only=True)
class Meta:
model = AcknowledgementContent
fields = [
"id",
"category",
"category_name_en",
"category_name_ar",
"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):
category_name_en = serializers.CharField(source="category.name_en", read_only=True)
category_name_ar = serializers.CharField(source="category.name_ar", 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",
"category",
"category_name_en",
"category_name_ar",
"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)
pdf_download_url = serializers.SerializerMethodField()
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",
"pdf_file",
"pdf_download_url",
"metadata",
"created_at",
"updated_at",
]
read_only_fields = ["id", "user", "acknowledged_at", "pdf_file", "created_at", "updated_at"]
def get_pdf_download_url(self, obj):
"""Get PDF download URL if available"""
if obj.pdf_file:
request = self.context.get("request")
if request:
return request.build_absolute_uri(f"/api/accounts/user-acknowledgements/{obj.id}/download_pdf/")
return None
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)