373 lines
11 KiB
Python
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)
|