Files
Iliyan Angelov 6b247e5b9f Updates
2025-09-19 11:58:53 +03:00

344 lines
16 KiB
Python

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