Files
ETB/ETB-API/collaboration_war_rooms/admin.py
Iliyan Angelov 6b247e5b9f Updates
2025-09-19 11:58:53 +03:00

280 lines
9.5 KiB
Python

"""
Admin configuration for Collaboration & War Rooms module
"""
from django.contrib import admin
from django.utils.html import format_html
from .models import (
WarRoom, ConferenceBridge, IncidentCommandRole,
TimelineEvent, WarRoomMessage, IncidentDecision
)
@admin.register(WarRoom)
class WarRoomAdmin(admin.ModelAdmin):
"""Admin interface for WarRoom model"""
list_display = [
'name', 'incident_title', 'status', 'privacy_level',
'message_count', 'active_participants', 'created_at'
]
list_filter = ['status', 'privacy_level', 'created_at']
search_fields = ['name', 'description', 'incident__title']
readonly_fields = ['id', 'created_at', 'updated_at', 'message_count', 'last_activity']
fieldsets = (
('Basic Information', {
'fields': ('id', 'name', 'description', 'incident')
}),
('Configuration', {
'fields': ('status', 'privacy_level', 'required_clearance_level')
}),
('Integrations', {
'fields': ('slack_channel_id', 'teams_channel_id', 'discord_channel_id'),
'classes': ('collapse',)
}),
('Access Control', {
'fields': ('allowed_users',),
'classes': ('collapse',)
}),
('Activity Tracking', {
'fields': ('message_count', 'last_activity', 'active_participants'),
'classes': ('collapse',)
}),
('Metadata', {
'fields': ('created_by', 'created_at', 'updated_at', 'archived_at'),
'classes': ('collapse',)
}),
)
def incident_title(self, obj):
"""Display incident title"""
return obj.incident.title
incident_title.short_description = 'Incident'
@admin.register(ConferenceBridge)
class ConferenceBridgeAdmin(admin.ModelAdmin):
"""Admin interface for ConferenceBridge model"""
list_display = [
'name', 'incident_title', 'bridge_type', 'status',
'scheduled_start', 'participant_count'
]
list_filter = ['bridge_type', 'status', 'recording_enabled', 'transcription_enabled']
search_fields = ['name', 'description', 'incident__title']
readonly_fields = ['id', 'created_at', 'updated_at', 'actual_start', 'actual_end']
fieldsets = (
('Basic Information', {
'fields': ('id', 'name', 'description', 'incident', 'war_room')
}),
('Bridge Configuration', {
'fields': ('bridge_type', 'status', 'integration_config')
}),
('Meeting Details', {
'fields': ('meeting_id', 'meeting_url', 'dial_in_number', 'access_code')
}),
('Schedule', {
'fields': ('scheduled_start', 'scheduled_end', 'actual_start', 'actual_end')
}),
('Participants', {
'fields': ('invited_participants', 'active_participants', 'max_participants'),
'classes': ('collapse',)
}),
('Recording & Transcription', {
'fields': ('recording_enabled', 'recording_url', 'transcription_enabled', 'transcription_url'),
'classes': ('collapse',)
}),
('Metadata', {
'fields': ('created_by', 'created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def incident_title(self, obj):
"""Display incident title"""
return obj.incident.title
incident_title.short_description = 'Incident'
def participant_count(self, obj):
"""Display participant count"""
return obj.invited_participants.count()
participant_count.short_description = 'Participants'
@admin.register(IncidentCommandRole)
class IncidentCommandRoleAdmin(admin.ModelAdmin):
"""Admin interface for IncidentCommandRole model"""
list_display = [
'role_type', 'incident_title', 'assigned_user', 'status',
'decisions_made', 'assigned_at'
]
list_filter = ['role_type', 'status', 'assigned_at']
search_fields = ['incident__title', 'assigned_user__username']
readonly_fields = [
'id', 'assigned_at', 'reassigned_at', 'reassigned_by',
'decisions_made', 'communications_sent', 'last_activity',
'created_at', 'updated_at'
]
fieldsets = (
('Basic Information', {
'fields': ('id', 'incident', 'war_room', 'role_type', 'assigned_user', 'status')
}),
('Role Configuration', {
'fields': ('responsibilities', 'decision_authority'),
'classes': ('collapse',)
}),
('Assignment Tracking', {
'fields': ('assigned_at', 'reassigned_at', 'reassigned_by', 'assignment_notes'),
'classes': ('collapse',)
}),
('Performance Tracking', {
'fields': ('decisions_made', 'communications_sent', 'last_activity'),
'classes': ('collapse',)
}),
('Metadata', {
'fields': ('created_by', 'created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def incident_title(self, obj):
"""Display incident title"""
return obj.incident.title
incident_title.short_description = 'Incident'
@admin.register(TimelineEvent)
class TimelineEventAdmin(admin.ModelAdmin):
"""Admin interface for TimelineEvent model"""
list_display = [
'event_time', 'title', 'incident_title', 'event_type',
'source_type', 'is_critical_event'
]
list_filter = ['event_type', 'source_type', 'is_critical_event', 'event_time']
search_fields = ['title', 'description', 'incident__title']
readonly_fields = ['id', 'created_at']
fieldsets = (
('Basic Information', {
'fields': ('id', 'incident', 'event_type', 'title', 'description', 'source_type')
}),
('Timing', {
'fields': ('event_time', 'created_at')
}),
('Related Objects', {
'fields': (
'related_user', 'related_runbook_execution', 'related_auto_remediation',
'related_sla_instance', 'related_escalation', 'related_war_room',
'related_conference', 'related_command_role'
),
'classes': ('collapse',)
}),
('Event Data', {
'fields': ('event_data', 'tags'),
'classes': ('collapse',)
}),
('Postmortem', {
'fields': ('is_critical_event', 'postmortem_notes'),
'classes': ('collapse',)
}),
('Metadata', {
'fields': ('created_by',),
'classes': ('collapse',)
}),
)
def incident_title(self, obj):
"""Display incident title"""
return obj.incident.title
incident_title.short_description = 'Incident'
@admin.register(WarRoomMessage)
class WarRoomMessageAdmin(admin.ModelAdmin):
"""Admin interface for WarRoomMessage model"""
list_display = [
'sender_name', 'war_room_name', 'message_type', 'content_preview', 'created_at'
]
list_filter = ['message_type', 'is_edited', 'created_at']
search_fields = ['content', 'sender_name', 'war_room__name']
readonly_fields = ['id', 'created_at', 'updated_at', 'is_edited', 'edited_at']
fieldsets = (
('Basic Information', {
'fields': ('id', 'war_room', 'message_type', 'content')
}),
('Sender Information', {
'fields': ('sender', 'sender_name')
}),
('Message Metadata', {
'fields': ('is_edited', 'edited_at', 'reply_to'),
'classes': ('collapse',)
}),
('Integration Data', {
'fields': ('external_message_id', 'external_data'),
'classes': ('collapse',)
}),
('Timestamps', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def war_room_name(self, obj):
"""Display war room name"""
return obj.war_room.name
war_room_name.short_description = 'War Room'
def content_preview(self, obj):
"""Display content preview"""
return obj.content[:50] + '...' if len(obj.content) > 50 else obj.content
content_preview.short_description = 'Content Preview'
@admin.register(IncidentDecision)
class IncidentDecisionAdmin(admin.ModelAdmin):
"""Admin interface for IncidentDecision model"""
list_display = [
'title', 'incident_title', 'decision_type', 'status',
'approved_by', 'implemented_by', 'created_at'
]
list_filter = ['decision_type', 'status', 'requires_approval', 'created_at']
search_fields = ['title', 'description', 'incident__title']
readonly_fields = [
'id', 'approved_by', 'approved_at', 'implemented_at',
'implemented_by', 'created_at', 'updated_at'
]
fieldsets = (
('Basic Information', {
'fields': ('id', 'incident', 'command_role', 'decision_type', 'title', 'description', 'rationale')
}),
('Decision Status', {
'fields': ('status', 'requires_approval', 'approved_by', 'approved_at')
}),
('Implementation', {
'fields': ('implementation_notes', 'implemented_at', 'implemented_by'),
'classes': ('collapse',)
}),
('Impact Tracking', {
'fields': ('impact_assessment', 'success_metrics'),
'classes': ('collapse',)
}),
('Timestamps', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',)
}),
)
def incident_title(self, obj):
"""Display incident title"""
return obj.incident.title
incident_title.short_description = 'Incident'