""" Django admin configuration for compliance_governance app """ from django.contrib import admin from django.utils.html import format_html from django.urls import reverse from django.utils.safestring import mark_safe from django.db.models import Count, Q from django.utils import timezone from datetime import timedelta from .models import ( RegulatoryFramework, ComplianceRequirement, RegulatoryWorkflow, WorkflowInstance, EvidenceCollection, RetentionPolicy, ExportRequest, ComplianceReport, LegalHold, ) @admin.register(RegulatoryFramework) class RegulatoryFrameworkAdmin(admin.ModelAdmin): """Admin interface for Regulatory Framework""" list_display = [ 'name', 'framework_type', 'version', 'is_active', 'effective_date', 'requirements_count', 'created_at' ] list_filter = [ 'framework_type', 'is_active', 'effective_date', 'created_at' ] search_fields = ['name', 'description', 'applicable_regions', 'industry_sectors'] readonly_fields = ['id', 'created_at', 'updated_at'] fieldsets = ( ('Basic Information', { 'fields': ('id', 'name', 'framework_type', 'version', 'description') }), ('Framework Details', { 'fields': ('applicable_regions', 'industry_sectors', 'compliance_requirements') }), ('Status and Dates', { 'fields': ('is_active', 'effective_date', 'review_date') }), ('Metadata', { 'fields': ('created_by', 'created_at', 'updated_at'), 'classes': ('collapse',) }), ) def requirements_count(self, obj): """Display count of requirements""" count = obj.requirements.count() if count > 0: url = reverse('admin:compliance_governance_compliancerequirement_changelist') return format_html('{} requirements', url, obj.id, count) return '0 requirements' requirements_count.short_description = 'Requirements' @admin.register(ComplianceRequirement) class ComplianceRequirementAdmin(admin.ModelAdmin): """Admin interface for Compliance Requirement""" list_display = [ 'requirement_id', 'title', 'framework', 'requirement_type', 'priority', 'compliance_status', 'is_implemented', 'assigned_to', 'next_assessment_date' ] list_filter = [ 'framework', 'requirement_type', 'priority', 'compliance_status', 'is_implemented', 'assigned_to', 'next_assessment_date' ] search_fields = ['requirement_id', 'title', 'description', 'responsible_team'] readonly_fields = ['id', 'created_at', 'updated_at'] fieldsets = ( ('Basic Information', { 'fields': ('id', 'framework', 'requirement_id', 'title', 'description') }), ('Requirement Details', { 'fields': ('requirement_type', 'priority', 'implementation_guidance', 'evidence_requirements', 'testing_procedures') }), ('Compliance Tracking', { 'fields': ('is_implemented', 'implementation_date', 'last_assessment_date', 'next_assessment_date', 'compliance_status') }), ('Assignment', { 'fields': ('responsible_team', 'assigned_to') }), ('Metadata', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }), ) def get_queryset(self, request): return super().get_queryset(request).select_related('framework', 'assigned_to') @admin.register(RegulatoryWorkflow) class RegulatoryWorkflowAdmin(admin.ModelAdmin): """Admin interface for Regulatory Workflow""" list_display = [ 'name', 'workflow_type', 'status', 'version', 'is_template', 'instances_count', 'created_by', 'created_at' ] list_filter = [ 'workflow_type', 'status', 'is_template', 'created_at' ] search_fields = ['name', 'description'] readonly_fields = ['id', 'created_at', 'updated_at'] filter_horizontal = ['applicable_frameworks'] def instances_count(self, obj): """Display count of workflow instances""" count = obj.instances.count() if count > 0: url = reverse('admin:compliance_governance_workflowinstance_changelist') return format_html('{} instances', url, obj.id, count) return '0 instances' instances_count.short_description = 'Instances' @admin.register(WorkflowInstance) class WorkflowInstanceAdmin(admin.ModelAdmin): """Admin interface for Workflow Instance""" list_display = [ 'title', 'workflow', 'status', 'assigned_to', 'related_incident', 'started_at', 'due_date', 'is_overdue' ] list_filter = [ 'workflow', 'status', 'assigned_to', 'started_at', 'due_date' ] search_fields = ['title', 'description', 'current_step'] readonly_fields = ['id', 'started_at', 'updated_at'] filter_horizontal = ['stakeholders'] def is_overdue(self, obj): """Check if workflow instance is overdue""" if obj.due_date and obj.status in ['PENDING', 'IN_PROGRESS']: if timezone.now() > obj.due_date: return format_html('Yes') return 'No' is_overdue.short_description = 'Overdue' @admin.register(EvidenceCollection) class EvidenceCollectionAdmin(admin.ModelAdmin): """Admin interface for Evidence Collection""" list_display = [ 'title', 'evidence_type', 'status', 'incident', 'collected_by', 'collection_timestamp', 'file_size_display' ] list_filter = [ 'evidence_type', 'status', 'collected_by', 'collection_timestamp' ] search_fields = ['title', 'description', 'collection_notes'] readonly_fields = ['id', 'collection_timestamp', 'created_at', 'updated_at'] def file_size_display(self, obj): """Display file size in human readable format""" if not obj.file_size: return 'N/A' size = obj.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" file_size_display.short_description = 'File Size' @admin.register(RetentionPolicy) class RetentionPolicyAdmin(admin.ModelAdmin): """Admin interface for Retention Policy""" list_display = [ 'name', 'policy_type', 'retention_period', 'retention_unit', 'is_active', 'effective_date', 'created_by' ] list_filter = [ 'policy_type', 'is_active', 'effective_date', 'created_at' ] search_fields = ['name', 'description'] readonly_fields = ['id', 'created_at', 'updated_at'] filter_horizontal = ['applicable_frameworks'] @admin.register(ExportRequest) class ExportRequestAdmin(admin.ModelAdmin): """Admin interface for Export Request""" list_display = [ 'title', 'request_type', 'status', 'requester_name', 'requester_organization', 'requested_at', 'due_date', 'is_overdue' ] list_filter = [ 'request_type', 'status', 'requester_organization', 'requested_at', 'due_date' ] search_fields = ['title', 'description', 'requester_name', 'requester_email'] readonly_fields = ['id', 'requested_at', 'updated_at'] filter_horizontal = ['applicable_frameworks'] def is_overdue(self, obj): """Check if export request is overdue""" if obj.due_date and obj.status not in ['COMPLETED', 'CANCELLED']: if timezone.now() > obj.due_date: return format_html('Yes') return 'No' is_overdue.short_description = 'Overdue' @admin.register(ComplianceReport) class ComplianceReportAdmin(admin.ModelAdmin): """Admin interface for Compliance Report""" list_display = [ 'title', 'report_type', 'framework', 'status', 'overall_compliance_score', 'report_period_start', 'report_period_end', 'prepared_by' ] list_filter = [ 'report_type', 'status', 'framework', 'report_period_start', 'report_period_end' ] search_fields = ['title', 'description', 'executive_summary'] readonly_fields = ['id', 'created_at', 'updated_at'] filter_horizontal = ['applicable_requirements'] @admin.register(LegalHold) class LegalHoldAdmin(admin.ModelAdmin): """Admin interface for Legal Hold""" list_display = [ 'case_name', 'case_number', 'status', 'legal_counsel', 'hold_date', 'expiration_date', 'affected_data_count', 'is_active' ] list_filter = [ 'status', 'hold_date', 'expiration_date', 'created_at' ] search_fields = ['case_name', 'case_number', 'description', 'legal_counsel', 'law_firm'] readonly_fields = ['id', 'created_at', 'updated_at'] filter_horizontal = ['related_incidents', 'related_evidence'] def affected_data_count(self, obj): """Display count of affected data items""" count = obj.get_affected_data_count() return f"{count} items" affected_data_count.short_description = 'Affected Data' def is_active(self, obj): """Check if legal hold is active""" if obj.is_active(): return format_html('Active') return format_html('Inactive') is_active.short_description = 'Status' # Custom admin site configuration admin.site.site_header = "ETB Compliance & Governance Administration" admin.site.site_title = "ETB Compliance Admin" admin.site.index_title = "Compliance & Governance Management"