344 lines
16 KiB
Python
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)
|