""" Serializers for Compliance & Governance API endpoints """ from rest_framework import serializers from django.contrib.auth import get_user_model from ..models import ( RegulatoryFramework, ComplianceRequirement, RegulatoryWorkflow, WorkflowInstance, EvidenceCollection, RetentionPolicy, ExportRequest, ComplianceReport, LegalHold, ) User = get_user_model() class RegulatoryFrameworkSerializer(serializers.ModelSerializer): """Serializer for Regulatory Framework""" requirements_count = serializers.SerializerMethodField() is_active_display = serializers.CharField(source='get_is_active_display', read_only=True) framework_type_display = serializers.CharField(source='get_framework_type_display', read_only=True) class Meta: model = RegulatoryFramework fields = [ 'id', 'name', 'framework_type', 'framework_type_display', 'version', 'description', 'applicable_regions', 'industry_sectors', 'compliance_requirements', 'is_active', 'is_active_display', 'effective_date', 'review_date', 'created_at', 'updated_at', 'created_by', 'requirements_count' ] read_only_fields = ['id', 'created_at', 'updated_at'] def get_requirements_count(self, obj): return obj.requirements.count() class ComplianceRequirementSerializer(serializers.ModelSerializer): """Serializer for Compliance Requirement""" framework_name = serializers.CharField(source='framework.name', read_only=True) requirement_type_display = serializers.CharField(source='get_requirement_type_display', read_only=True) priority_display = serializers.CharField(source='get_priority_display', read_only=True) compliance_status_display = serializers.CharField(source='get_compliance_status_display', read_only=True) assigned_to_name = serializers.CharField(source='assigned_to.get_full_name', read_only=True) class Meta: model = ComplianceRequirement fields = [ 'id', 'framework', 'framework_name', 'requirement_id', 'title', 'description', 'requirement_type', 'requirement_type_display', 'priority', 'priority_display', 'implementation_guidance', 'evidence_requirements', 'testing_procedures', 'is_implemented', 'implementation_date', 'last_assessment_date', 'next_assessment_date', 'compliance_status', 'compliance_status_display', 'responsible_team', 'assigned_to', 'assigned_to_name', 'created_at', 'updated_at' ] read_only_fields = ['id', 'created_at', 'updated_at'] class RegulatoryWorkflowSerializer(serializers.ModelSerializer): """Serializer for Regulatory Workflow""" workflow_type_display = serializers.CharField(source='get_workflow_type_display', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) applicable_frameworks_names = serializers.StringRelatedField( source='applicable_frameworks', many=True, read_only=True ) instances_count = serializers.SerializerMethodField() created_by_name = serializers.CharField(source='created_by.get_full_name', read_only=True) class Meta: model = RegulatoryWorkflow fields = [ 'id', 'name', 'workflow_type', 'workflow_type_display', 'description', 'applicable_frameworks', 'applicable_frameworks_names', 'workflow_definition', 'triggers', 'conditions', 'status', 'status_display', 'version', 'is_template', 'notification_rules', 'escalation_rules', 'created_at', 'updated_at', 'created_by', 'created_by_name', 'instances_count' ] read_only_fields = ['id', 'created_at', 'updated_at'] def get_instances_count(self, obj): return obj.instances.count() class WorkflowInstanceSerializer(serializers.ModelSerializer): """Serializer for Workflow Instance""" workflow_name = serializers.CharField(source='workflow.name', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) related_incident_title = serializers.CharField(source='related_incident.title', read_only=True) related_requirement_title = serializers.CharField(source='related_requirement.title', read_only=True) assigned_to_name = serializers.CharField(source='assigned_to.get_full_name', read_only=True) created_by_name = serializers.CharField(source='created_by.get_full_name', read_only=True) stakeholders_names = serializers.StringRelatedField( source='stakeholders', many=True, read_only=True ) is_overdue = serializers.SerializerMethodField() class Meta: model = WorkflowInstance fields = [ 'id', 'workflow', 'workflow_name', 'title', 'description', 'status', 'status_display', 'related_incident', 'related_incident_title', 'related_requirement', 'related_requirement_title', 'current_step', 'execution_data', 'completed_steps', 'assigned_to', 'assigned_to_name', 'stakeholders', 'stakeholders_names', 'started_at', 'completed_at', 'due_date', 'is_overdue', 'created_by', 'created_by_name', 'updated_at' ] read_only_fields = ['id', 'started_at', 'updated_at'] def get_is_overdue(self, obj): if not obj.due_date: return False from django.utils import timezone return timezone.now() > obj.due_date and obj.status not in ['COMPLETED', 'CANCELLED'] class EvidenceCollectionSerializer(serializers.ModelSerializer): """Serializer for Evidence Collection""" evidence_type_display = serializers.CharField(source='get_evidence_type_display', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) incident_title = serializers.CharField(source='incident.title', read_only=True) workflow_instance_title = serializers.CharField(source='workflow_instance.title', read_only=True) compliance_requirement_title = serializers.CharField(source='compliance_requirement.title', read_only=True) collected_by_name = serializers.CharField(source='collected_by.get_full_name', read_only=True) verified_by_name = serializers.CharField(source='verified_by.get_full_name', read_only=True) file_size_display = serializers.SerializerMethodField() class Meta: model = EvidenceCollection fields = [ 'id', 'title', 'description', 'evidence_type', 'evidence_type_display', 'status', 'status_display', 'incident', 'incident_title', 'workflow_instance', 'workflow_instance_title', 'compliance_requirement', 'compliance_requirement_title', 'file_path', 'file_hash', 'file_size', 'file_size_display', 'mime_type', 'collection_method', 'collection_timestamp', 'collection_location', 'collection_notes', 'collected_by', 'collected_by_name', 'verified_by', 'verified_by_name', 'custody_chain', 'retention_period', 'disposal_date', 'disposal_method', 'created_at', 'updated_at' ] read_only_fields = ['id', 'collection_timestamp', 'created_at', 'updated_at'] def get_file_size_display(self, obj): if not obj.file_size: return None # Convert bytes to human readable format for unit in ['B', 'KB', 'MB', 'GB', 'TB']: if obj.file_size < 1024.0: return f"{obj.file_size:.1f} {unit}" obj.file_size /= 1024.0 return f"{obj.file_size:.1f} PB" class RetentionPolicySerializer(serializers.ModelSerializer): """Serializer for Retention Policy""" policy_type_display = serializers.CharField(source='get_policy_type_display', read_only=True) retention_unit_display = serializers.CharField(source='get_retention_unit_display', read_only=True) applicable_frameworks_names = serializers.StringRelatedField( source='applicable_frameworks', many=True, read_only=True ) created_by_name = serializers.CharField(source='created_by.get_full_name', read_only=True) retention_duration_display = serializers.SerializerMethodField() class Meta: model = RetentionPolicy fields = [ 'id', 'name', 'description', 'policy_type', 'policy_type_display', 'applicable_frameworks', 'applicable_frameworks_names', 'retention_period', 'retention_unit', 'retention_unit_display', 'retention_duration_display', 'auto_archive', 'auto_delete', 'data_classification_levels', 'incident_categories', 'custom_filters', 'legal_hold_override', 'exception_conditions', 'is_active', 'effective_date', 'review_date', 'created_at', 'updated_at', 'created_by', 'created_by_name' ] read_only_fields = ['id', 'created_at', 'updated_at'] def get_retention_duration_display(self, obj): duration = obj.get_retention_duration() days = duration.days if days >= 365: years = days // 365 return f"{years} year{'s' if years > 1 else ''}" elif days >= 30: months = days // 30 return f"{months} month{'s' if months > 1 else ''}" elif days >= 7: weeks = days // 7 return f"{weeks} week{'s' if weeks > 1 else ''}" else: return f"{days} day{'s' if days > 1 else ''}" class ExportRequestSerializer(serializers.ModelSerializer): """Serializer for Export Request""" request_type_display = serializers.CharField(source='get_request_type_display', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) applicable_frameworks_names = serializers.StringRelatedField( source='applicable_frameworks', many=True, read_only=True ) approved_by_name = serializers.CharField(source='approved_by.get_full_name', read_only=True) executed_by_name = serializers.CharField(source='executed_by.get_full_name', read_only=True) created_by_name = serializers.CharField(source='created_by.get_full_name', read_only=True) is_overdue = serializers.SerializerMethodField() export_file_size_display = serializers.SerializerMethodField() class Meta: model = ExportRequest fields = [ 'id', 'title', 'description', 'request_type', 'request_type_display', 'status', 'status_display', 'requester_name', 'requester_organization', 'requester_email', 'requester_phone', 'legal_authority', 'data_scope', 'date_range_start', 'date_range_end', 'data_classification_levels', 'incident_categories', 'applicable_frameworks', 'applicable_frameworks_names', 'export_format', 'include_evidence', 'include_audit_trails', 'redaction_required', 'approval_required', 'approved_by', 'approved_by_name', 'approved_at', 'approval_notes', 'executed_by', 'executed_by_name', 'export_file_path', 'export_file_hash', 'export_file_size', 'export_file_size_display', 'requested_at', 'due_date', 'is_overdue', 'completed_at', 'created_by', 'created_by_name', 'updated_at' ] read_only_fields = ['id', 'requested_at', 'updated_at'] def get_is_overdue(self, obj): return obj.is_overdue() def get_export_file_size_display(self, obj): if not obj.export_file_size: return None # Convert bytes to human readable format size = obj.export_file_size for unit in ['B', 'KB', 'MB', 'GB', 'TB']: if size < 1024.0: return f"{size:.1f} {unit}" size /= 1024.0 return f"{size:.1f} PB" class ComplianceReportSerializer(serializers.ModelSerializer): """Serializer for Compliance Report""" report_type_display = serializers.CharField(source='get_report_type_display', read_only=True) status_display = serializers.CharField(source='get_status_display', read_only=True) framework_name = serializers.CharField(source='framework.name', read_only=True) applicable_requirements_titles = serializers.StringRelatedField( source='applicable_requirements', many=True, read_only=True ) prepared_by_name = serializers.CharField(source='prepared_by.get_full_name', read_only=True) reviewed_by_name = serializers.CharField(source='reviewed_by.get_full_name', read_only=True) approved_by_name = serializers.CharField(source='approved_by.get_full_name', read_only=True) class Meta: model = ComplianceReport fields = [ 'id', 'title', 'report_type', 'report_type_display', 'description', 'status', 'status_display', 'framework', 'framework_name', 'applicable_requirements', 'applicable_requirements_titles', 'executive_summary', 'findings', 'recommendations', 'action_items', 'overall_compliance_score', 'compliance_gaps', 'risk_assessment', 'report_period_start', 'report_period_end', 'report_file_path', 'prepared_by', 'prepared_by_name', 'reviewed_by', 'reviewed_by_name', 'approved_by', 'approved_by_name', 'created_at', 'updated_at', 'published_at' ] read_only_fields = ['id', 'created_at', 'updated_at'] class LegalHoldSerializer(serializers.ModelSerializer): """Serializer for Legal Hold""" status_display = serializers.CharField(source='get_status_display', read_only=True) related_incidents_titles = serializers.StringRelatedField( source='related_incidents', many=True, read_only=True ) related_evidence_titles = serializers.StringRelatedField( source='related_evidence', many=True, read_only=True ) created_by_name = serializers.CharField(source='created_by.get_full_name', read_only=True) is_active = serializers.SerializerMethodField() affected_data_count = serializers.SerializerMethodField() class Meta: model = LegalHold fields = [ 'id', 'case_name', 'case_number', 'description', 'status', 'status_display', 'legal_counsel', 'law_firm', 'court_jurisdiction', 'data_scope', 'custodian_list', 'search_criteria', 'hold_date', 'release_date', 'expiration_date', 'related_incidents', 'related_incidents_titles', 'related_evidence', 'related_evidence_titles', 'notification_sent', 'notification_date', 'reminder_sent', 'reminder_date', 'is_active', 'affected_data_count', 'created_by', 'created_by_name', 'created_at', 'updated_at' ] read_only_fields = ['id', 'created_at', 'updated_at'] def get_is_active(self, obj): return obj.is_active() def get_affected_data_count(self, obj): return obj.get_affected_data_count() # Nested serializers for detailed views class ComplianceRequirementDetailSerializer(ComplianceRequirementSerializer): """Detailed serializer for Compliance Requirement with related data""" framework = RegulatoryFrameworkSerializer(read_only=True) evidence_collection = EvidenceCollectionSerializer(many=True, read_only=True) workflow_instances = WorkflowInstanceSerializer(many=True, read_only=True) class WorkflowInstanceDetailSerializer(WorkflowInstanceSerializer): """Detailed serializer for Workflow Instance with related data""" workflow = RegulatoryWorkflowSerializer(read_only=True) evidence_collection = EvidenceCollectionSerializer(many=True, read_only=True) class EvidenceCollectionDetailSerializer(EvidenceCollectionSerializer): """Detailed serializer for Evidence Collection with related data""" incident = serializers.StringRelatedField(read_only=True) workflow_instance = WorkflowInstanceSerializer(read_only=True) compliance_requirement = ComplianceRequirementSerializer(read_only=True) class ExportRequestDetailSerializer(ExportRequestSerializer): """Detailed serializer for Export Request with related data""" applicable_frameworks = RegulatoryFrameworkSerializer(many=True, read_only=True) class ComplianceReportDetailSerializer(ComplianceReportSerializer): """Detailed serializer for Compliance Report with related data""" framework = RegulatoryFrameworkSerializer(read_only=True) applicable_requirements = ComplianceRequirementSerializer(many=True, read_only=True) class LegalHoldDetailSerializer(LegalHoldSerializer): """Detailed serializer for Legal Hold with related data""" related_incidents = serializers.StringRelatedField(many=True, read_only=True) related_evidence = EvidenceCollectionSerializer(many=True, read_only=True)