""" Admin interface for integrations app. """ from django.contrib import admin from django.utils.html import format_html from django.urls import reverse from django.db.models import Count from .models import ( IntegrationProvider, IntegrationCredential, IntegrationLog, WebhookEndpoint, WebhookEvent, RateLimitRule ) @admin.register(IntegrationProvider) class IntegrationProviderAdmin(admin.ModelAdmin): list_display = [ 'name', 'slug', 'provider_type', 'status_badge', 'credentials_count', 'webhooks_count', 'created_at' ] list_filter = ['provider_type', 'status', 'created_at'] search_fields = ['name', 'slug', 'description'] readonly_fields = ['id', 'created_at', 'updated_at'] prepopulated_fields = {'slug': ('name',)} fieldsets = ( ('Main Info', { 'fields': ('id', 'name', 'slug', 'provider_type', 'status') }), ('API Settings', { 'fields': ('api_base_url', 'documentation_url') }), ('Description', { 'fields': ('description',) }), ('Timestamps', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }) ) def status_badge(self, obj): colors = { 'active': 'green', 'inactive': 'red', 'maintenance': 'orange' } color = colors.get(obj.status, 'gray') return format_html( ' {}', color, obj.get_status_display() ) status_badge.short_description = 'Status' def credentials_count(self, obj): count = obj.credentials.filter(is_active=True).count() url = reverse('admin:integrations_integrationcredential_changelist') return format_html( '{} Active', url, obj.id, count ) credentials_count.short_description = 'Credentials' def webhooks_count(self, obj): count = obj.webhooks.count() url = reverse('admin:integrations_webhookendpoint_changelist') return format_html( '{}', url, obj.id, count ) webhooks_count.short_description = 'Webhooks' @admin.register(IntegrationCredential) class IntegrationCredentialAdmin(admin.ModelAdmin): list_display = [ 'provider', 'key_name', 'environment', 'is_active', 'is_valid_badge', 'expires_at', 'created_by' ] list_filter = ['provider', 'environment', 'is_active', 'is_encrypted'] search_fields = ['key_name', 'provider__name'] readonly_fields = ['id', 'created_at', 'updated_at', 'created_by'] fieldsets = ( ('Credentials Info', { 'fields': ('id', 'provider', 'key_name', 'key_value') }), ('Settings', { 'fields': ('environment', 'is_encrypted', 'is_active', 'expires_at') }), ('Metadata', { 'fields': ('created_by', 'created_at', 'updated_at'), 'classes': ('collapse',) }) ) def is_valid_badge(self, obj): if obj.is_valid(): return format_html('✓ Valid') return format_html('✗ Invalid') is_valid_badge.short_description = 'Validity' def save_model(self, request, obj, form, change): if not change: obj.created_by = request.user super().save_model(request, obj, form, change) @admin.register(IntegrationLog) class IntegrationLogAdmin(admin.ModelAdmin): list_display = [ 'created_at', 'provider', 'log_level_badge', 'service_name', 'action', 'status_code', 'duration_ms', 'user' ] list_filter = ['provider', 'log_level', 'service_name', 'created_at'] search_fields = ['action', 'error_message', 'user__username'] readonly_fields = [ 'id', 'provider', 'log_level', 'service_name', 'action', 'request_data_formatted', 'response_data_formatted', 'error_message', 'status_code', 'duration_ms', 'user', 'ip_address', 'created_at' ] date_hierarchy = 'created_at' fieldsets = ( ('Log Info', { 'fields': ( 'id', 'provider', 'log_level', 'service_name', 'action', 'created_at' ) }), ('Payload Details', { 'fields': ( 'request_data_formatted', 'response_data_formatted', 'status_code', 'duration_ms' ), 'classes': ('collapse',) }), ('Failure / Error', { 'fields': ('error_message',), 'classes': ('collapse',) }), ('User Info', { 'fields': ('user', 'ip_address'), 'classes': ('collapse',) }) ) def log_level_badge(self, obj): colors = { 'debug': 'gray', 'info': 'blue', 'warning': 'orange', 'error': 'red', 'critical': 'darkred' } color = colors.get(obj.log_level, 'black') return format_html( '{}', color, obj.get_log_level_display() ) log_level_badge.short_description = 'Level' def request_data_formatted(self, obj): import json try: return format_html( '
{}
', json.dumps(obj.request_data, indent=2, ensure_ascii=False) ) except: return str(obj.request_data) request_data_formatted.short_description = 'Request Data' def response_data_formatted(self, obj): import json try: return format_html( '
{}
', json.dumps(obj.response_data, indent=2, ensure_ascii=False) ) except: return str(obj.response_data) response_data_formatted.short_description = 'Response Data' def has_add_permission(self, request) -> bool: return False def has_change_permission(self, request, obj=None) -> bool: return False @admin.register(WebhookEndpoint) class WebhookEndpointAdmin(admin.ModelAdmin): list_display = [ 'name', 'provider', 'endpoint_url', 'is_active', 'events_count', 'pending_events', 'created_at' ] list_filter = ['provider', 'is_active', 'created_at'] search_fields = ['name', 'endpoint_url', 'provider__name'] readonly_fields = ['id', 'created_at', 'updated_at'] fieldsets = ( ('Main Info', { 'fields': ('id', 'provider', 'name', 'endpoint_url') }), ('Security', { 'fields': ('secret_key',), 'classes': ('collapse',) }), ('Config', { 'fields': ('events', 'is_active', 'retry_count', 'timeout_seconds') }), ('Timestamps', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }) ) def get_queryset(self, request): qs = super().get_queryset(request) return qs.annotate( _events_count=Count('events_received'), _pending_count=Count('events_received', filter=Count('events_received', filter=Count('events_received', filter=Count('events_received')))) # Note: simple filter annotation is better ) def events_count(self, obj): count = obj.events_received.count() url = reverse('admin:integrations_webhookevent_changelist') return format_html( '{}', url, obj.id, count ) events_count.short_description = 'Events' def pending_events(self, obj): count = obj.events_received.filter(is_processed=False).count() if count > 0: return format_html('{} Pending', count) return '0' pending_events.short_description = 'Pending' @admin.register(WebhookEvent) class WebhookEventAdmin(admin.ModelAdmin): list_display = [ 'received_at', 'webhook', 'event_type', 'is_valid_badge', 'is_processed_badge', 'retry_count', 'processed_at' ] list_filter = [ 'webhook__provider', 'webhook', 'event_type', 'is_valid', 'is_processed', 'received_at' ] search_fields = ['event_type', 'error_message', 'webhook__name'] readonly_fields = [ 'id', 'webhook', 'event_type', 'payload_formatted', 'headers_formatted', 'signature', 'is_valid', 'is_processed', 'processed_at', 'error_message', 'retry_count', 'received_at' ] date_hierarchy = 'received_at' fieldsets = ( ('Event Info', { 'fields': ('id', 'webhook', 'event_type', 'received_at') }), ('Content', { 'fields': ('payload_formatted', 'headers_formatted', 'signature'), 'classes': ('collapse',) }), ('Processing Status', { 'fields': ( 'is_valid', 'is_processed', 'processed_at', 'retry_count', 'error_message' ) }) ) def is_valid_badge(self, obj): if obj.is_valid: return format_html('') return format_html('') is_valid_badge.short_description = 'Valid' def is_processed_badge(self, obj): if obj.is_processed: return format_html('') return format_html('') is_processed_badge.short_description = 'Processed' def payload_formatted(self, obj): import json try: return format_html( '
{}
', json.dumps(obj.payload, indent=2, ensure_ascii=False) ) except: return str(obj.payload) payload_formatted.short_description = 'Payload' def headers_formatted(self, obj): import json try: return format_html( '
{}
', json.dumps(obj.headers, indent=2, ensure_ascii=False) ) except: return str(obj.headers) headers_formatted.short_description = 'Headers' def has_add_permission(self, request) -> bool: return False def has_change_permission(self, request, obj=None) -> bool: return False @admin.register(RateLimitRule) class RateLimitRuleAdmin(admin.ModelAdmin): list_display = [ 'name', 'provider', 'endpoint_pattern', 'rate_description', 'scope', 'is_active', 'created_at' ] list_filter = ['provider', 'scope', 'is_active', 'created_at'] search_fields = ['name', 'endpoint_pattern', 'provider__name'] readonly_fields = ['id', 'created_at', 'updated_at'] fieldsets = ( ('Main Info', { 'fields': ('id', 'provider', 'name', 'endpoint_pattern') }), ('Rate Limits', { 'fields': ('max_requests', 'time_window_seconds', 'scope') }), ('Status', { 'fields': ('is_active',) }), ('Timestamps', { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }) ) def rate_description(self, obj) -> str: return f"{obj.max_requests} requests in {obj.time_window_seconds} seconds" rate_description.short_description = 'Limits' # Admin Site Header Customization admin.site.site_header = "Integrations Admin Portal" admin.site.site_title = "Integrations Admin" admin.site.index_title = "Integrations System Dashboard"