Marwan Alwali 2780a2dc7c update
2025-09-16 15:10:57 +03:00

2748 lines
96 KiB
Python

"""
Communications app views with comprehensive CRUD operations following healthcare best practices.
"""
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.views.generic import (
ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
)
from django.urls import reverse_lazy, reverse
from django.http import JsonResponse, HttpResponse
from django.db.models import Q, Count, Avg, Sum
from django.utils import timezone
from django.core.paginator import Paginator
from django.db import transaction
from datetime import datetime, timedelta, date
import json
from .models import (
Message, MessageRecipient, NotificationTemplate, AlertRule,
AlertInstance, CommunicationChannel, DeliveryLog
)
from .forms import (
MessageForm, NotificationTemplateForm, AlertRuleForm,
CommunicationChannelForm
)
# ============================================================================
# DASHBOARD AND OVERVIEW VIEWS
# ============================================================================
class CommunicationsDashboardView(LoginRequiredMixin, TemplateView):
"""
Main communications dashboard with comprehensive statistics and recent activity.
"""
template_name = 'communications/dashboard.html'
def get_context_data(self, **kwargs):
tenant = self.request.user.tenant
context = super().get_context_data(**kwargs)
# Basic statistics
context.update({
'total_messages': Message.objects.filter(tenant=tenant).count(),
'total_templates': NotificationTemplate.objects.filter(tenant=tenant).count(),
'total_channels': CommunicationChannel.objects.filter(
tenant=tenant,
is_active=True
).count(),
'total_alert_rules': AlertRule.objects.filter(tenant=tenant).count(),
})
# Recent activity
context.update({
'recent_messages': Message.objects.filter(
tenant=tenant
).order_by('-created_at')[:5],
'recent_alerts': AlertInstance.objects.filter(
alert_rule__tenant=tenant
).order_by('-triggered_at')[:5],
'recent_deliveries': DeliveryLog.objects.filter(
message__tenant=tenant
).order_by('-started_at')[:10],
})
# Message statistics
today = timezone.now().date()
context.update({
'messages_today': Message.objects.filter(
tenant=tenant,
created_at__date=today
).count(),
'successful_deliveries': DeliveryLog.objects.filter(
message__tenant=tenant,
completed_at__date=today,
status='DELIVERED'
).count(),
'failed_deliveries': DeliveryLog.objects.filter(
message__tenant=tenant,
completed_at__date=today,
status='FAILED'
).count(),
})
# Alert statistics
context.update({
'active_alerts': AlertInstance.objects.filter(
alert_rule__tenant=tenant,
status='ACTIVE'
).count(),
'resolved_alerts': AlertInstance.objects.filter(
alert_rule__tenant=tenant,
status='RESOLVED'
).count(),
})
return context
# ============================================================================
# MESSAGE VIEWS (FULL CRUD - Operational Data)
# ============================================================================
class MessageListView(LoginRequiredMixin, ListView):
"""
List all messages with filtering and search capabilities.
"""
model = Message
template_name = 'communications/message_list.html'
context_object_name = 'messages'
paginate_by = 20
def get_queryset(self):
queryset = Message.objects.filter(tenant=self.request.user.tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(subject__icontains=search) |
Q(body__icontains=search) |
Q(sender__username__icontains=search)
)
# Filter by message type
message_type = self.request.GET.get('message_type')
if message_type:
queryset = queryset.filter(message_type=message_type)
# Filter by priority
priority = self.request.GET.get('priority')
if priority:
queryset = queryset.filter(priority=priority)
# Filter by status
status = self.request.GET.get('status')
if status:
queryset = queryset.filter(status=status)
# Filter by date range
start_date = self.request.GET.get('start_date')
end_date = self.request.GET.get('end_date')
if start_date:
queryset = queryset.filter(created_at__date__gte=start_date)
if end_date:
queryset = queryset.filter(created_at__date__lte=end_date)
return queryset.select_related('sender').order_by('-created_at')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['search'] = self.request.GET.get('search', '')
context['selected_message_type'] = self.request.GET.get('message_type', '')
context['selected_priority'] = self.request.GET.get('priority', '')
context['selected_status'] = self.request.GET.get('status', '')
context['start_date'] = self.request.GET.get('start_date', '')
context['end_date'] = self.request.GET.get('end_date', '')
return context
class MessageDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific message.
"""
model = Message
template_name = 'communications/message_detail.html'
context_object_name = 'message'
def get_queryset(self):
return Message.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
message = self.get_object()
# Message recipients
context['recipients'] = MessageRecipient.objects.filter(
message=message
).select_related('recipient')
# Delivery logs
context['delivery_logs'] = DeliveryLog.objects.filter(
message=message
).order_by('-delivery_time')
# Delivery statistics
context['total_recipients'] = MessageRecipient.objects.filter(
message=message
).count()
context['delivered_count'] = DeliveryLog.objects.filter(
message=message,
status='DELIVERED'
).count()
context['failed_count'] = DeliveryLog.objects.filter(
message=message,
status='FAILED'
).count()
return context
class MessageCreateView(LoginRequiredMixin, CreateView):
"""
Create a new message.
"""
model = Message
form_class = MessageForm
template_name = 'communications/message_form.html'
success_url = reverse_lazy('communications:message_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
form.instance.sender = self.request.user
messages.success(self.request, 'Message created successfully.')
return super().form_valid(form)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
class MessageUpdateView(LoginRequiredMixin, UpdateView):
"""
Update an existing message (limited to draft messages).
"""
model = Message
form_class = MessageForm
template_name = 'communications/message_form.html'
def get_queryset(self):
# Only allow editing of draft messages
return Message.objects.filter(
tenant=self.request.user.tenant,
status='DRAFT'
)
def get_success_url(self):
return reverse('communications:message_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
messages.success(self.request, 'Message updated successfully.')
return super().form_valid(form)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
class MessageDeleteView(LoginRequiredMixin, DeleteView):
"""
Delete a message (only draft messages).
"""
model = Message
template_name = 'communications/message_confirm_delete.html'
success_url = reverse_lazy('communications:message_list')
def get_queryset(self):
# Only allow deletion of draft messages
return Message.objects.filter(
tenant=self.request.user.tenant,
status='DRAFT'
)
def delete(self, request, *args, **kwargs):
messages.success(request, 'Message deleted successfully.')
return super().delete(request, *args, **kwargs)
# ============================================================================
# NOTIFICATION TEMPLATE VIEWS (FULL CRUD - Master Data)
# ============================================================================
class NotificationTemplateListView(LoginRequiredMixin, ListView):
"""
List all notification templates with filtering capabilities.
"""
model = NotificationTemplate
template_name = 'communications/notification_template_list.html'
context_object_name = 'templates'
paginate_by = 20
def get_queryset(self):
queryset = NotificationTemplate.objects.filter(tenant=self.request.user.tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(template_name__icontains=search) |
Q(description__icontains=search)
)
# Filter by template type
template_type = self.request.GET.get('template_type')
if template_type:
queryset = queryset.filter(template_type=template_type)
# Filter by category
category = self.request.GET.get('category')
if category:
queryset = queryset.filter(category=category)
# Filter by status
is_active = self.request.GET.get('is_active')
if is_active:
queryset = queryset.filter(is_active=is_active == 'true')
return queryset.order_by('name')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['search'] = self.request.GET.get('search', '')
context['selected_template_type'] = self.request.GET.get('template_type', '')
context['selected_category'] = self.request.GET.get('category', '')
context['selected_is_active'] = self.request.GET.get('is_active', '')
return context
class NotificationTemplateDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific notification template.
"""
model = NotificationTemplate
template_name = 'communications/notification_template_detail.html'
context_object_name = 'template'
def get_queryset(self):
return NotificationTemplate.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
template = self.get_object()
# Usage statistics
context['messages_using_template'] = Message.objects.filter(
template=template
).count()
return context
class NotificationTemplateCreateView(LoginRequiredMixin, CreateView):
"""
Create a new notification template.
"""
model = NotificationTemplate
form_class = NotificationTemplateForm
template_name = 'communications/notification_template_form.html'
success_url = reverse_lazy('communications:notification_template_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
messages.success(self.request, 'Notification template created successfully.')
return super().form_valid(form)
class NotificationTemplateUpdateView(LoginRequiredMixin, UpdateView):
"""
Update an existing notification template.
"""
model = NotificationTemplate
form_class = NotificationTemplateForm
template_name = 'communications/notification_template_form.html'
def get_queryset(self):
return NotificationTemplate.objects.filter(tenant=self.request.user.tenant)
def get_success_url(self):
return reverse('communications:notification_template_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
messages.success(self.request, 'Notification template updated successfully.')
return super().form_valid(form)
class NotificationTemplateDeleteView(LoginRequiredMixin, DeleteView):
"""
Delete a notification template.
"""
model = NotificationTemplate
template_name = 'communications/notification_template_confirm_delete.html'
success_url = reverse_lazy('communications:notification_template_list')
def get_queryset(self):
return NotificationTemplate.objects.filter(tenant=self.request.user.tenant)
def delete(self, request, *args, **kwargs):
template = self.get_object()
# Check if template is used by messages
if Message.objects.filter(template=template).exists():
messages.error(request, 'Cannot delete template that is used by messages.')
return redirect('communications:notification_template_detail', pk=template.pk)
messages.success(request, f'Notification template {template.template_name} deleted successfully.')
return super().delete(request, *args, **kwargs)
# ============================================================================
# ALERT RULE VIEWS (FULL CRUD - Master Data)
# ============================================================================
class AlertRuleListView(LoginRequiredMixin, ListView):
"""
List all alert rules with filtering capabilities.
"""
model = AlertRule
template_name = 'communications/alert_rule_list.html'
context_object_name = 'alert_rules'
paginate_by = 20
def get_queryset(self):
queryset = AlertRule.objects.filter(tenant=self.request.user.tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(rule_name__icontains=search) |
Q(description__icontains=search)
)
# Filter by severity
severity = self.request.GET.get('severity')
if severity:
queryset = queryset.filter(severity=severity)
# Filter by category
category = self.request.GET.get('category')
if category:
queryset = queryset.filter(category=category)
# Filter by status
is_active = self.request.GET.get('is_active')
if is_active:
queryset = queryset.filter(is_active=is_active == 'true')
return queryset.order_by('name')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['search'] = self.request.GET.get('search', '')
context['selected_severity'] = self.request.GET.get('severity', '')
context['selected_category'] = self.request.GET.get('category', '')
context['selected_is_active'] = self.request.GET.get('is_active', '')
return context
class AlertRuleDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific alert rule.
"""
model = AlertRule
template_name = 'communications/alert_rule_detail.html'
context_object_name = 'alert_rule'
def get_queryset(self):
return AlertRule.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
alert_rule = self.get_object()
# Recent alert instances
context['recent_alerts'] = AlertInstance.objects.filter(
alert_rule=alert_rule
).order_by('-created_at')[:10]
# Alert statistics
context['total_alerts'] = AlertInstance.objects.filter(
alert_rule=alert_rule
).count()
context['active_alerts'] = AlertInstance.objects.filter(
alert_rule=alert_rule,
status='ACTIVE'
).count()
return context
class AlertRuleCreateView(LoginRequiredMixin, CreateView):
"""
Create a new alert rule.
"""
model = AlertRule
form_class = AlertRuleForm
template_name = 'communications/alert_rule_form.html'
success_url = reverse_lazy('communications:alert_rule_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
messages.success(self.request, 'Alert rule created successfully.')
return super().form_valid(form)
class AlertRuleUpdateView(LoginRequiredMixin, UpdateView):
"""
Update an existing alert rule.
"""
model = AlertRule
form_class = AlertRuleForm
template_name = 'communications/alert_rule_form.html'
def get_queryset(self):
return AlertRule.objects.filter(tenant=self.request.user.tenant)
def get_success_url(self):
return reverse('communications:alert_rule_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
messages.success(self.request, 'Alert rule updated successfully.')
return super().form_valid(form)
class AlertRuleDeleteView(LoginRequiredMixin, DeleteView):
"""
Delete an alert rule.
"""
model = AlertRule
template_name = 'communications/alert_rule_confirm_delete.html'
success_url = reverse_lazy('communications:alert_rule_list')
def get_queryset(self):
return AlertRule.objects.filter(tenant=self.request.user.tenant)
def delete(self, request, *args, **kwargs):
messages.success(request, 'Alert rule deleted successfully.')
return super().delete(request, *args, **kwargs)
# ============================================================================
# ALERT INSTANCE VIEWS (APPEND-ONLY - System Generated)
# ============================================================================
class AlertInstanceListView(LoginRequiredMixin, ListView):
"""
List all alert instances with filtering capabilities.
"""
model = AlertInstance
template_name = 'communications/alert_instance_list.html'
context_object_name = 'alert_instances'
paginate_by = 20
def get_queryset(self):
queryset = AlertInstance.objects.filter(tenant=self.request.user.tenant)
# Filter by alert rule
alert_rule = self.request.GET.get('alert_rule')
if alert_rule:
queryset = queryset.filter(alert_rule_id=alert_rule)
# Filter by severity
severity = self.request.GET.get('severity')
if severity:
queryset = queryset.filter(severity=severity)
# Filter by status
status = self.request.GET.get('status')
if status:
queryset = queryset.filter(status=status)
# Filter by date range
start_date = self.request.GET.get('start_date')
end_date = self.request.GET.get('end_date')
if start_date:
queryset = queryset.filter(created_at__date__gte=start_date)
if end_date:
queryset = queryset.filter(created_at__date__lte=end_date)
return queryset.select_related('alert_rule').order_by('-created_at')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['alert_rules'] = AlertRule.objects.filter(
tenant=self.request.user.tenant
).order_by('rule_name')
context['selected_alert_rule'] = self.request.GET.get('alert_rule', '')
context['selected_severity'] = self.request.GET.get('severity', '')
context['selected_status'] = self.request.GET.get('status', '')
context['start_date'] = self.request.GET.get('start_date', '')
context['end_date'] = self.request.GET.get('end_date', '')
return context
class AlertInstanceDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific alert instance.
"""
model = AlertInstance
template_name = 'communications/alert_instance_detail.html'
context_object_name = 'alert_instance'
def get_queryset(self):
return AlertInstance.objects.filter(tenant=self.request.user.tenant)
# ============================================================================
# COMMUNICATION CHANNEL VIEWS (FULL CRUD - Master Data)
# ============================================================================
class CommunicationChannelListView(LoginRequiredMixin, ListView):
"""
List all communication channels with filtering capabilities.
"""
model = CommunicationChannel
template_name = 'communications/communication_channel_list.html'
context_object_name = 'channels'
paginate_by = 20
def get_queryset(self):
queryset = CommunicationChannel.objects.filter(tenant=self.request.user.tenant)
# Search functionality
search = self.request.GET.get('search')
if search:
queryset = queryset.filter(
Q(channel_name__icontains=search) |
Q(description__icontains=search)
)
# Filter by channel type
channel_type = self.request.GET.get('channel_type')
if channel_type:
queryset = queryset.filter(channel_type=channel_type)
# Filter by status
is_active = self.request.GET.get('is_active')
if is_active:
queryset = queryset.filter(is_active=is_active == 'true')
return queryset.order_by('name')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['search'] = self.request.GET.get('search', '')
context['selected_channel_type'] = self.request.GET.get('channel_type', '')
context['selected_is_active'] = self.request.GET.get('is_active', '')
return context
class CommunicationChannelDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific communication channel.
"""
model = CommunicationChannel
template_name = 'communications/communication_channel_detail.html'
context_object_name = 'channel'
def get_queryset(self):
return CommunicationChannel.objects.filter(tenant=self.request.user.tenant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
channel = self.get_object()
# Recent delivery logs
context['recent_deliveries'] = DeliveryLog.objects.filter(
channel=channel
).order_by('-delivery_time')[:10]
# Delivery statistics
context['total_deliveries'] = DeliveryLog.objects.filter(
channel=channel
).count()
context['successful_deliveries'] = DeliveryLog.objects.filter(
channel=channel,
status='DELIVERED'
).count()
return context
class CommunicationChannelCreateView(LoginRequiredMixin, CreateView):
"""
Create a new communication channel.
"""
model = CommunicationChannel
form_class = CommunicationChannelForm
template_name = 'communications/communication_channel_form.html'
success_url = reverse_lazy('communications:communication_channel_list')
def form_valid(self, form):
form.instance.tenant = self.request.user.tenant
messages.success(self.request, 'Communication channel created successfully.')
return super().form_valid(form)
class CommunicationChannelUpdateView(LoginRequiredMixin, UpdateView):
"""
Update an existing communication channel.
"""
model = CommunicationChannel
form_class = CommunicationChannelForm
template_name = 'communications/communication_channel_form.html'
def get_queryset(self):
return CommunicationChannel.objects.filter(tenant=self.request.user.tenant)
def get_success_url(self):
return reverse('communications:communication_channel_detail', kwargs={'pk': self.object.pk})
def form_valid(self, form):
messages.success(self.request, 'Communication channel updated successfully.')
return super().form_valid(form)
class CommunicationChannelDeleteView(LoginRequiredMixin, DeleteView):
"""
Delete a communication channel.
"""
model = CommunicationChannel
template_name = 'communications/communication_channel_confirm_delete.html'
success_url = reverse_lazy('communications:communication_channel_list')
def get_queryset(self):
return CommunicationChannel.objects.filter(tenant=self.request.user.tenant)
def delete(self, request, *args, **kwargs):
messages.success(request, 'Communication channel deleted successfully.')
return super().delete(request, *args, **kwargs)
# ============================================================================
# DELIVERY LOG VIEWS (READ-ONLY - System Generated)
# ============================================================================
class DeliveryLogListView(LoginRequiredMixin, ListView):
"""
List all delivery logs (read-only).
"""
model = DeliveryLog
template_name = 'communications/delivery_log_list.html'
context_object_name = 'delivery_logs'
paginate_by = 20
def get_queryset(self):
tenant = self.request.user.tenant
queryset = DeliveryLog.objects.filter(message__tenant=tenant)
# Filter by message
message = self.request.GET.get('message')
if message:
queryset = queryset.filter(message_id=message)
# Filter by channel
channel = self.request.GET.get('channel')
if channel:
queryset = queryset.filter(channel_id=channel)
# Filter by status
status = self.request.GET.get('status')
if status:
queryset = queryset.filter(status=status)
# Filter by date range
start_date = self.request.GET.get('start_date')
end_date = self.request.GET.get('end_date')
if start_date:
queryset = queryset.filter(completed_at__date__gte=start_date)
if end_date:
queryset = queryset.filter(completed_at__date__lte=end_date)
return queryset.select_related('message', 'channel', 'recipient').order_by('-completed_at')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['messages'] = Message.objects.filter(
tenant=self.request.user.tenant
).order_by('-created_at')[:50]
context['channels'] = CommunicationChannel.objects.filter(
tenant=self.request.user.tenant
).order_by('name')
context['selected_message'] = self.request.GET.get('message', '')
context['selected_channel'] = self.request.GET.get('channel', '')
context['selected_status'] = self.request.GET.get('status', '')
context['start_date'] = self.request.GET.get('start_date', '')
context['end_date'] = self.request.GET.get('end_date', '')
return context
class DeliveryLogDetailView(LoginRequiredMixin, DetailView):
"""
Display detailed information about a specific delivery log.
"""
model = DeliveryLog
template_name = 'communications/delivery_log_detail.html'
context_object_name = 'delivery_log'
def get_queryset(self):
return DeliveryLog.objects.filter(tenant=self.request.user.tenant)
# ============================================================================
# HTMX VIEWS FOR REAL-TIME UPDATES
# ============================================================================
@login_required
def communications_stats(request):
"""
Return communications statistics for dashboard updates.
"""
today = timezone.now().date()
context = {
'total_messages': Message.objects.filter(tenant=request.user.tenant).count(),
'total_templates': NotificationTemplate.objects.filter(tenant=request.user.tenant).count(),
'total_channels': CommunicationChannel.objects.filter(
tenant=request.user.tenant,
is_active=True
).count(),
'total_alert_rules': AlertRule.objects.filter(tenant=request.user.tenant).count(),
'messages_today': Message.objects.filter(
tenant=request.user.tenant,
created_at__date=today
).count(),
'successful_deliveries': DeliveryLog.objects.filter(
tenant=request.user.tenant,
delivery_time__date=today,
status='DELIVERED'
).count(),
'active_alerts': AlertInstance.objects.filter(
tenant=request.user.tenant,
status='ACTIVE'
).count(),
}
return render(request, 'communications/partials/communications_stats.html', context)
@login_required
def message_search(request):
"""
Search messages for HTMX updates.
"""
search = request.GET.get('search', '')
messages_qs = Message.objects.filter(
tenant=request.user.tenant
)
if search:
messages_qs = messages_qs.filter(
Q(subject__icontains=search) |
Q(body__icontains=search) |
Q(sender__username__icontains=search)
)
messages_qs = messages_qs.select_related('sender')[:20]
return render(request, 'communications/partials/message_list.html', {
'messages': messages_qs
})
@login_required
def recent_messages(request):
tenant = request.user.tenant
messages_qs = Message.objects.filter(
tenant=tenant,
status='DRAFT'
)
recent_messages = messages_qs.order_by('-created_at')[:10]
return JsonResponse({'recent_messages': recent_messages})
@login_required
def send_message(request, message_id):
"""
Send a message.
"""
try:
message = Message.objects.get(
id=message_id,
tenant=request.user.tenant,
status='DRAFT'
)
# Update message status
message.status = 'SENT'
message.sent_at = timezone.now()
message.save()
# Create delivery logs for recipients (simulate sending)
recipients = MessageRecipient.objects.filter(message=message)
for recipient in recipients:
DeliveryLog.objects.create(
tenant=request.user.tenant,
message=message,
recipient=recipient.recipient,
channel=None, # Would be determined by message type
delivery_time=timezone.now(),
status='DELIVERED'
)
messages.success(request, f'Message "{message.subject}" sent successfully.')
except Message.DoesNotExist:
messages.error(request, 'Message not found or cannot be sent.')
return redirect('communications:message_detail', pk=message_id)
@login_required
def test_channel(request, channel_id):
"""
Test a communication channel.
"""
try:
channel = CommunicationChannel.objects.get(
id=channel_id,
tenant=request.user.tenant
)
# Simulate channel test (implement actual logic based on channel type)
channel.last_test_time = timezone.now()
channel.last_test_status = 'SUCCESS'
channel.last_test_message = 'Test successful'
channel.save()
messages.success(request, f'Channel {channel.channel_name} tested successfully.')
except CommunicationChannel.DoesNotExist:
messages.error(request, 'Communication channel not found.')
return redirect('communications:communication_channel_detail', pk=channel_id)
@login_required
def acknowledge_alert(request, alert_id):
"""
Acknowledge an alert instance.
"""
try:
alert = AlertInstance.objects.get(
id=alert_id,
tenant=request.user.tenant
)
alert.status = 'ACKNOWLEDGED'
alert.acknowledged_by = request.user
alert.acknowledged_at = timezone.now()
alert.save()
messages.success(request, 'Alert acknowledged successfully.')
except AlertInstance.DoesNotExist:
messages.error(request, 'Alert instance not found.')
return redirect('communications:alert_instance_detail', pk=alert_id)
@login_required
def resolve_alert(request, alert_id):
"""
Resolve an alert instance.
"""
try:
alert = AlertInstance.objects.get(
id=alert_id,
tenant=request.user.tenant
)
alert.status = 'RESOLVED'
alert.resolved_by = request.user
alert.resolved_at = timezone.now()
alert.save()
messages.success(request, 'Alert resolved successfully.')
except AlertInstance.DoesNotExist:
messages.error(request, 'Alert instance not found.')
return redirect('communications:alert_instance_detail', pk=alert_id)
#
# from django.shortcuts import render, redirect, get_object_or_404
# from django.views.generic import (
# ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
# )
# from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
# from django.contrib.auth.decorators import login_required
# from django.contrib import messages
# from django.urls import reverse_lazy, reverse
# from django.utils import timezone
# from django.http import JsonResponse, HttpResponse
# from django.db.models import Count, Q, F
# from django.core.paginator import Paginator
# from django.utils.translation import gettext_lazy as _
# from rest_framework import viewsets, permissions, status
# from rest_framework.decorators import action
# from rest_framework.response import Response
#
# from core.utils import AuditLogger
# from .models import (
# Message,
# MessageRecipient,
# NotificationTemplate,
# AlertRule,
# AlertInstance,
# CommunicationChannel,
# DeliveryLog
# )
# from .forms import (
# MessageForm,
# NotificationTemplateForm,
# CommunicationChannelForm,
# AlertRuleForm,
# AlertInstanceForm,
# SendMessageForm
# )
# # from .serializers import (
# # MessageSerializer,
# # NotificationTemplateSerializer,
# # AlertRuleSerializer,
# # AlertInstanceSerializer,
# # CommunicationChannelSerializer,
# # CommunicationsStatsSerializer,
# # NotificationSendSerializer
# # )
#
#
# class CommunicationsDashboardView(LoginRequiredMixin, TemplateView):
# """
# Main dashboard for communications module.
# """
# template_name = 'communications/dashboard.html'
#
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# user = self.request.user
# tenant_filter = {}
#
# if hasattr(user, 'tenant') and user.tenant:
# tenant_filter['tenant'] = user.tenant
#
# # Get recent messages
# context['recent_messages'] = Message.objects.filter(
# **tenant_filter
# ).order_by('-created_at')[:10]
#
# # Get active alerts
# context['active_alerts'] = AlertInstance.objects.filter(
# **tenant_filter,
# status__in=['ACTIVE', 'ACKNOWLEDGED', 'ESCALATED']
# ).order_by('-triggered_at')[:5]
#
# # Get notification templates
# context['templates'] = NotificationTemplate.objects.filter(
# **tenant_filter,
# is_active=True
# ).order_by('-created_at')[:5]
#
# # Get communication channels
# context['channels'] = CommunicationChannel.objects.filter(
# **tenant_filter,
# is_active=True
# ).order_by('-created_at')[:5]
#
# # Add send message form
# context['send_message_form'] = SendMessageForm(user=user)
#
# return context
#
#
# class MessageListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# List view for messages.
# """
# model = Message
# template_name = 'communications/message_list.html'
# context_object_name = 'messages'
# permission_required = 'communications.view_message'
# paginate_by = 20
#
# def get_queryset(self):
# """Filter messages by tenant and search criteria."""
# queryset = Message.objects.all()
# user = self.request.user
#
# # Filter by tenant
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# # Handle search
# search_query = self.request.GET.get('q')
# if search_query:
# queryset = queryset.filter(
# Q(subject__icontains=search_query) |
# Q(body__icontains=search_query) |
# Q(sender__first_name__icontains=search_query) |
# Q(sender__last_name__icontains=search_query) |
# Q(sender__email__icontains=search_query)
# )
#
# # Handle filters
# message_type = self.request.GET.get('type')
# if message_type:
# queryset = queryset.filter(message_type=message_type)
#
# status_filter = self.request.GET.get('status')
# if status_filter:
# if status_filter == 'draft':
# queryset = queryset.filter(is_draft=True)
# elif status_filter == 'scheduled':
# queryset = queryset.filter(
# is_draft=False,
# scheduled_send_time__isnull=False,
# sent_at__isnull=True
# )
# elif status_filter == 'sent':
# queryset = queryset.filter(sent_at__isnull=False)
# elif status_filter == 'pending':
# queryset = queryset.filter(
# is_draft=False,
# scheduled_send_time__isnull=True,
# sent_at__isnull=True
# )
#
# # Handle date range
# start_date = self.request.GET.get('start_date')
# end_date = self.request.GET.get('end_date')
#
# if start_date:
# queryset = queryset.filter(created_at__gte=start_date)
# if end_date:
# queryset = queryset.filter(created_at__lte=end_date)
#
# return queryset.select_related('sender', 'template').order_by('-created_at')
#
# def get_context_data(self, **kwargs):
# """Add filter options to context."""
# context = super().get_context_data(**kwargs)
# user = self.request.user
# tenant_filter = {}
#
# if hasattr(user, 'tenant') and user.tenant:
# tenant_filter['tenant'] = user.tenant
#
# # Add message type choices
# context['message_types'] = Message.MESSAGE_TYPE_CHOICES
#
# # Add status filter choices
# context['status_filters'] = [
# ('draft', _('Draft')),
# ('scheduled', _('Scheduled')),
# ('sent', _('Sent')),
# ('pending', _('Pending'))
# ]
#
# # Add current filters to context
# context['current_filters'] = {
# 'q': self.request.GET.get('q', ''),
# 'type': self.request.GET.get('type', ''),
# 'status': self.request.GET.get('status', ''),
# 'start_date': self.request.GET.get('start_date', ''),
# 'end_date': self.request.GET.get('end_date', '')
# }
#
# # Add counts for different statuses
# context['draft_count'] = Message.objects.filter(
# **tenant_filter, is_draft=True
# ).count()
#
# context['scheduled_count'] = Message.objects.filter(
# **tenant_filter,
# is_draft=False,
# scheduled_send_time__isnull=False,
# sent_at__isnull=True
# ).count()
#
# context['sent_count'] = Message.objects.filter(
# **tenant_filter, sent_at__isnull=False
# ).count()
#
# context['pending_count'] = Message.objects.filter(
# **tenant_filter,
# is_draft=False,
# scheduled_send_time__isnull=True,
# sent_at__isnull=True
# ).count()
#
# return context
#
#
# class MessageDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# Detail view for messages.
# """
# model = Message
# template_name = 'communications/message_detail.html'
# context_object_name = 'message'
# permission_required = 'communications.view_message'
#
# def get_queryset(self):
# """Filter by tenant."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset.select_related('sender', 'template')
#
# def get_context_data(self, **kwargs):
# """Add recipients and delivery logs to context."""
# context = super().get_context_data(**kwargs)
# message = self.object
#
# # Get recipients with prefetched related objects
# context['recipients'] = MessageRecipient.objects.filter(
# message=message
# ).select_related('recipient', 'channel')
#
# # Get delivery logs
# context['delivery_logs'] = DeliveryLog.objects.filter(
# message=message
# ).select_related('channel').order_by('-last_attempt_at')
#
# # Calculate delivery stats
# recipient_count = context['recipients'].count()
# delivered_count = context['recipients'].filter(status='DELIVERED').count()
# failed_count = context['recipients'].filter(status__in=['FAILED', 'BOUNCED', 'REJECTED']).count()
# pending_count = recipient_count - delivered_count - failed_count
#
# context['delivery_stats'] = {
# 'total': recipient_count,
# 'delivered': delivered_count,
# 'failed': failed_count,
# 'pending': pending_count,
# 'success_rate': (delivered_count / recipient_count * 100) if recipient_count > 0 else 0
# }
#
# return context
#
#
# class MessageCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create view for messages.
# """
# model = Message
# form_class = MessageForm
# template_name = 'communications/message_form.html'
# permission_required = 'communications.add_message'
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def form_valid(self, form):
# """Handle valid form, create message and recipients."""
# response = super().form_valid(form)
#
# # Log the action
# message_type = form.cleaned_data.get('message_type')
# AuditLogger.log_action(
# user=self.request.user,
# action='MESSAGE_CREATED',
# model='Message',
# object_id=str(self.object.message_id),
# details={
# 'message_type': message_type,
# 'is_draft': form.cleaned_data.get('is_draft'),
# 'scheduled': bool(form.cleaned_data.get('scheduled_send_time'))
# }
# )
#
# # Display success message
# if form.cleaned_data.get('is_draft'):
# messages.success(self.request, _("Message draft saved successfully."))
# elif form.cleaned_data.get('scheduled_send_time'):
# messages.success(self.request, _("Message scheduled successfully."))
# else:
# messages.success(self.request, _("Message sent successfully."))
#
# return response
#
# def get_success_url(self):
# """Return to message list or detail view based on status."""
# if self.object.is_draft:
# return reverse('communications:message_update', args=[self.object.pk])
# return reverse('communications:message_detail', args=[self.object.pk])
#
#
# class MessageUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update view for messages.
# """
# model = Message
# form_class = MessageForm
# template_name = 'communications/message_form.html'
# permission_required = 'communications.change_message'
#
# def get_queryset(self):
# """Filter by tenant and only allow editing drafts or scheduled messages."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# # Only allow editing drafts or scheduled messages that haven't been sent
# return queryset.filter(
# Q(is_draft=True) |
# Q(scheduled_send_time__isnull=False, sent_at__isnull=True)
# )
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def form_valid(self, form):
# """Handle valid form, update message and recipients."""
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='MESSAGE_UPDATED',
# model='Message',
# object_id=str(self.object.message_id),
# details={
# 'message_type': form.cleaned_data.get('message_type'),
# 'is_draft': form.cleaned_data.get('is_draft'),
# 'scheduled': bool(form.cleaned_data.get('scheduled_send_time'))
# }
# )
#
# # Display success message
# if form.cleaned_data.get('is_draft'):
# messages.success(self.request, _("Message draft updated successfully."))
# elif form.cleaned_data.get('scheduled_send_time'):
# messages.success(self.request, _("Scheduled message updated successfully."))
# else:
# messages.success(self.request, _("Message updated and sent successfully."))
#
# return response
#
# def get_success_url(self):
# """Return to message list or detail view based on status."""
# if self.object.is_draft:
# return reverse('communications:message_update', args=[self.object.pk])
# return reverse('communications:message_detail', args=[self.object.pk])
#
#
# class MessageDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete view for messages.
# """
# model = Message
# template_name = 'communications/message_confirm_delete.html'
# context_object_name = 'message'
# permission_required = 'communications.delete_message'
# success_url = reverse_lazy('communications:message_list')
#
# def get_queryset(self):
# """Filter by tenant and only allow deleting drafts or scheduled messages."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# # Only allow deleting drafts or scheduled messages that haven't been sent
# return queryset.filter(
# Q(is_draft=True) |
# Q(scheduled_send_time__isnull=False, sent_at__isnull=True)
# )
#
# def delete(self, request, *args, **kwargs):
# """Handle delete request, log action."""
# message = self.get_object()
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='MESSAGE_DELETED',
# model='Message',
# object_id=str(message.message_id),
# details={
# 'subject': message.subject,
# 'message_type': message.message_type,
# 'is_draft': message.is_draft
# }
# )
#
# # Display success message
# messages.success(self.request, _("Message deleted successfully."))
#
# return super().delete(request, *args, **kwargs)
#
#
# class NotificationTemplateListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# List view for notification templates.
# """
# model = NotificationTemplate
# template_name = 'communications/template_list.html'
# context_object_name = 'templates'
# permission_required = 'communications.view_notificationtemplate'
# paginate_by = 20
#
# def get_queryset(self):
# """Filter templates by tenant and search criteria."""
# queryset = NotificationTemplate.objects.all()
# user = self.request.user
#
# # Filter by tenant
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# # Handle search
# search_query = self.request.GET.get('q')
# if search_query:
# queryset = queryset.filter(
# Q(name__icontains=search_query) |
# Q(description__icontains=search_query) |
# Q(subject_template__icontains=search_query) |
# Q(body_template__icontains=search_query)
# )
#
# # Handle template type filter
# template_type = self.request.GET.get('type')
# if template_type:
# queryset = queryset.filter(template_type=template_type)
#
# # Handle active status filter
# active_filter = self.request.GET.get('active')
# if active_filter:
# is_active = (active_filter.lower() == 'true')
# queryset = queryset.filter(is_active=is_active)
#
# return queryset.select_related('default_channel', 'created_by').order_by('-created_at')
#
# def get_context_data(self, **kwargs):
# """Add filter options to context."""
# context = super().get_context_data(**kwargs)
#
# # Add template type choices
# context['template_types'] = NotificationTemplate.TEMPLATE_TYPE_CHOICES
#
# # Add current filters to context
# context['current_filters'] = {
# 'q': self.request.GET.get('q', ''),
# 'type': self.request.GET.get('type', ''),
# 'active': self.request.GET.get('active', '')
# }
#
# return context
#
#
# class NotificationTemplateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# Detail view for notification templates.
# """
# model = NotificationTemplate
# template_name = 'communications/template_detail.html'
# context_object_name = 'template'
# permission_required = 'communications.view_notificationtemplate'
#
# def get_queryset(self):
# """Filter by tenant."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset.select_related('default_channel', 'created_by')
#
# def get_context_data(self, **kwargs):
# """Add additional context."""
# context = super().get_context_data(**kwargs)
# template = self.object
#
# # Get recent messages using this template
# context['recent_messages'] = Message.objects.filter(
# template=template
# ).order_by('-created_at')[:5]
#
# # Get alert rules using this template
# context['alert_rules'] = AlertRule.objects.filter(
# template=template
# ).order_by('-created_at')[:5]
#
# # Add sample variables for preview
# sample_variables = {}
# for var in template.variables:
# sample_variables[var] = f"[{var}]"
#
# context['sample_variables'] = sample_variables
#
# # Add preview of rendered template
# try:
# rendered = template.render(sample_variables)
# context['preview'] = rendered
# except Exception as e:
# context['preview_error'] = str(e)
#
# return context
#
#
# class NotificationTemplateCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create view for notification templates.
# """
# model = NotificationTemplate
# form_class = NotificationTemplateForm
# template_name = 'communications/template_form.html'
# permission_required = 'communications.add_notificationtemplate'
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def form_valid(self, form):
# """Handle valid form, create template."""
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='TEMPLATE_CREATED',
# model='NotificationTemplate',
# object_id=str(self.object.template_id),
# details={
# 'name': self.object.name,
# 'template_type': self.object.template_type
# }
# )
#
# # Display success message
# messages.success(self.request, _("Notification template created successfully."))
#
# return response
#
# def get_success_url(self):
# """Return to template detail view."""
# return reverse('communications:template_detail', args=[self.object.pk])
#
#
# class NotificationTemplateUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update view for notification templates.
# """
# model = NotificationTemplate
# form_class = NotificationTemplateForm
# template_name = 'communications/template_form.html'
# permission_required = 'communications.change_notificationtemplate'
#
# def get_queryset(self):
# """Filter by tenant."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def form_valid(self, form):
# """Handle valid form, update template."""
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='TEMPLATE_UPDATED',
# model='NotificationTemplate',
# object_id=str(self.object.template_id),
# details={
# 'name': self.object.name,
# 'template_type': self.object.template_type
# }
# )
#
# # Display success message
# messages.success(self.request, _("Notification template updated successfully."))
#
# return response
#
# def get_success_url(self):
# """Return to template detail view."""
# return reverse('communications:template_detail', args=[self.object.pk])
#
#
# class NotificationTemplateDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete view for notification templates.
# """
# model = NotificationTemplate
# template_name = 'communications/template_confirm_delete.html'
# context_object_name = 'template'
# permission_required = 'communications.delete_notificationtemplate'
# success_url = reverse_lazy('communications:template_list')
#
# def get_queryset(self):
# """Filter by tenant."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset
#
# def delete(self, request, *args, **kwargs):
# """Handle delete request, log action."""
# template = self.get_object()
#
# # Check if template is in use
# messages_using_template = Message.objects.filter(template=template).count()
# alert_rules_using_template = AlertRule.objects.filter(template=template).count()
#
# if messages_using_template > 0 or alert_rules_using_template > 0:
# messages.error(
# self.request,
# _("Cannot delete template that is in use by messages or alert rules.")
# )
# return redirect('communications:template_detail', pk=template.pk)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='TEMPLATE_DELETED',
# model='NotificationTemplate',
# object_id=str(template.template_id),
# details={
# 'name': template.name,
# 'template_type': template.template_type
# }
# )
#
# # Display success message
# messages.success(self.request, _("Notification template deleted successfully."))
#
# return super().delete(request, *args, **kwargs)
#
#
# class CommunicationChannelListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# List view for communication channels.
# """
# model = CommunicationChannel
# template_name = 'communications/channel_list.html'
# context_object_name = 'channels'
# permission_required = 'communications.view_communicationchannel'
# paginate_by = 20
#
# def get_queryset(self):
# """Filter channels by tenant and search criteria."""
# queryset = CommunicationChannel.objects.all()
# user = self.request.user
#
# # Filter by tenant
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# # Handle search
# search_query = self.request.GET.get('q')
# if search_query:
# queryset = queryset.filter(
# Q(name__icontains=search_query) |
# Q(description__icontains=search_query)
# )
#
# # Handle channel type filter
# channel_type = self.request.GET.get('type')
# if channel_type:
# queryset = queryset.filter(channel_type=channel_type)
#
# # Handle provider type filter
# provider_type = self.request.GET.get('provider')
# if provider_type:
# queryset = queryset.filter(provider_type=provider_type)
#
# # Handle health status filter
# health_filter = self.request.GET.get('health')
# if health_filter:
# is_healthy = (health_filter.lower() == 'healthy')
# queryset = queryset.filter(is_healthy=is_healthy)
#
# # Handle active status filter
# active_filter = self.request.GET.get('active')
# if active_filter:
# is_active = (active_filter.lower() == 'true')
# queryset = queryset.filter(is_active=is_active)
#
# return queryset.select_related('created_by').order_by('-created_at')
#
# def get_context_data(self, **kwargs):
# """Add filter options to context."""
# context = super().get_context_data(**kwargs)
#
# # Add channel type choices
# context['channel_types'] = CommunicationChannel.CHANNEL_TYPE_CHOICES
#
# # Add provider type choices
# context['provider_types'] = CommunicationChannel.PROVIDER_TYPE_CHOICES
#
# # Add current filters to context
# context['current_filters'] = {
# 'q': self.request.GET.get('q', ''),
# 'type': self.request.GET.get('type', ''),
# 'provider': self.request.GET.get('provider', ''),
# 'health': self.request.GET.get('health', ''),
# 'active': self.request.GET.get('active', '')
# }
#
# return context
#
#
# class CommunicationChannelDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# Detail view for communication channels.
# """
# model = CommunicationChannel
# template_name = 'communications/channel_detail.html'
# context_object_name = 'channel'
# permission_required = 'communications.view_communicationchannel'
#
# def get_queryset(self):
# """Filter by tenant."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset.select_related('created_by')
#
# def get_context_data(self, **kwargs):
# """Add additional context."""
# context = super().get_context_data(**kwargs)
# channel = self.object
#
# # Get recent delivery logs for this channel
# context['delivery_logs'] = DeliveryLog.objects.filter(
# channel=channel
# ).order_by('-last_attempt_at')[:10]
#
# # Get templates using this channel as default
# context['templates'] = NotificationTemplate.objects.filter(
# default_channel=channel
# ).order_by('-created_at')[:5]
#
# # Get alert rules using this channel
# context['alert_rules'] = AlertRule.objects.filter(
# notification_channels=channel
# ).order_by('-created_at')[:5]
#
# # Get delivery statistics
# total_logs = DeliveryLog.objects.filter(channel=channel).count()
# if total_logs > 0:
# success_logs = DeliveryLog.objects.filter(
# channel=channel, status='DELIVERED'
# ).count()
#
# context['delivery_stats'] = {
# 'total': total_logs,
# 'success': success_logs,
# 'failure': total_logs - success_logs,
# 'success_rate': (success_logs / total_logs * 100)
# }
#
# return context
#
#
# class CommunicationChannelCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create view for communication channels.
# """
# model = CommunicationChannel
# form_class = CommunicationChannelForm
# template_name = 'communications/channel_form.html'
# permission_required = 'communications.add_communicationchannel'
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def form_valid(self, form):
# """Handle valid form, create channel."""
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='CHANNEL_CREATED',
# model='CommunicationChannel',
# object_id=str(self.object.channel_id),
# details={
# 'name': self.object.name,
# 'channel_type': self.object.channel_type,
# 'provider_type': self.object.provider_type
# }
# )
#
# # Display success message
# messages.success(self.request, _("Communication channel created successfully."))
#
# return response
#
# def get_success_url(self):
# """Return to channel detail view."""
# return reverse('communications:channel_detail', args=[self.object.pk])
#
#
# class CommunicationChannelUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update view for communication channels.
# """
# model = CommunicationChannel
# form_class = CommunicationChannelForm
# template_name = 'communications/channel_form.html'
# permission_required = 'communications.change_communicationchannel'
#
# def get_queryset(self):
# """Filter by tenant."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def form_valid(self, form):
# """Handle valid form, update channel."""
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='CHANNEL_UPDATED',
# model='CommunicationChannel',
# object_id=str(self.object.channel_id),
# details={
# 'name': self.object.name,
# 'channel_type': self.object.channel_type,
# 'provider_type': self.object.provider_type
# }
# )
#
# # Display success message
# messages.success(self.request, _("Communication channel updated successfully."))
#
# return response
#
# def get_success_url(self):
# """Return to channel detail view."""
# return reverse('communications:channel_detail', args=[self.object.pk])
#
#
# class CommunicationChannelDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete view for communication channels.
# """
# model = CommunicationChannel
# template_name = 'communications/channel_confirm_delete.html'
# context_object_name = 'channel'
# permission_required = 'communications.delete_communicationchannel'
# success_url = reverse_lazy('communications:channel_list')
#
# def get_queryset(self):
# """Filter by tenant."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset
#
# def delete(self, request, *args, **kwargs):
# """Handle delete request, log action."""
# channel = self.get_object()
#
# # Check if channel is in use
# templates_using_channel = NotificationTemplate.objects.filter(
# default_channel=channel
# ).count()
#
# alert_rules_using_channel = AlertRule.objects.filter(
# notification_channels=channel
# ).count()
#
# if templates_using_channel > 0 or alert_rules_using_channel > 0:
# messages.error(
# self.request,
# _("Cannot delete channel that is in use by templates or alert rules.")
# )
# return redirect('communications:channel_detail', pk=channel.pk)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='CHANNEL_DELETED',
# model='CommunicationChannel',
# object_id=str(channel.channel_id),
# details={
# 'name': channel.name,
# 'channel_type': channel.channel_type,
# 'provider_type': channel.provider_type
# }
# )
#
# # Display success message
# messages.success(self.request, _("Communication channel deleted successfully."))
#
# return super().delete(request, *args, **kwargs)
#
#
# class AlertListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# List view for alert instances.
# """
# model = AlertInstance
# template_name = 'communications/alert_list.html'
# context_object_name = 'alerts'
# permission_required = 'communications.view_alertinstance'
# paginate_by = 20
#
# def get_queryset(self):
# """Filter alerts by tenant and search criteria."""
# queryset = AlertInstance.objects.all()
# user = self.request.user
#
# # Filter by tenant
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# # Handle search
# search_query = self.request.GET.get('q')
# if search_query:
# queryset = queryset.filter(
# Q(title__icontains=search_query) |
# Q(description__icontains=search_query) |
# Q(entity_id__icontains=search_query) |
# Q(rule__name__icontains=search_query)
# )
#
# # Handle status filter
# status_filter = self.request.GET.get('status')
# if status_filter:
# if status_filter == 'active':
# queryset = queryset.filter(status__in=['ACTIVE', 'ACKNOWLEDGED', 'ESCALATED'])
# else:
# queryset = queryset.filter(status=status_filter.upper())
#
# # Handle severity filter
# severity_filter = self.request.GET.get('severity')
# if severity_filter:
# queryset = queryset.filter(severity=severity_filter.upper())
#
# # Handle entity type filter
# entity_type = self.request.GET.get('entity_type')
# if entity_type:
# queryset = queryset.filter(entity_type=entity_type)
#
# # Handle date range
# start_date = self.request.GET.get('start_date')
# end_date = self.request.GET.get('end_date')
#
# if start_date:
# queryset = queryset.filter(triggered_at__gte=start_date)
# if end_date:
# queryset = queryset.filter(triggered_at__lte=end_date)
#
# return queryset.select_related(
# 'rule', 'acknowledged_by', 'resolved_by'
# ).order_by('-triggered_at')
#
# def get_context_data(self, **kwargs):
# """Add filter options to context."""
# context = super().get_context_data(**kwargs)
# user = self.request.user
# tenant_filter = {}
#
# if hasattr(user, 'tenant') and user.tenant:
# tenant_filter['tenant'] = user.tenant
#
# # Add status filter choices
# context['status_filters'] = [
# ('active', _('Active & Acknowledged')),
# ('ACTIVE', _('Active')),
# ('ACKNOWLEDGED', _('Acknowledged')),
# ('ESCALATED', _('Escalated')),
# ('RESOLVED', _('Resolved')),
# ('AUTO_RESOLVED', _('Auto-Resolved'))
# ]
#
# # Add severity choices
# context['severity_filters'] = AlertInstance.SEVERITY_CHOICES
#
# # Add entity types (dynamically from data)
# entity_types = AlertInstance.objects.filter(
# **tenant_filter
# ).values_list('entity_type', flat=True).distinct()
#
# context['entity_types'] = sorted(entity_types)
#
# # Add current filters to context
# context['current_filters'] = {
# 'q': self.request.GET.get('q', ''),
# 'status': self.request.GET.get('status', ''),
# 'severity': self.request.GET.get('severity', ''),
# 'entity_type': self.request.GET.get('entity_type', ''),
# 'start_date': self.request.GET.get('start_date', ''),
# 'end_date': self.request.GET.get('end_date', '')
# }
#
# # Add counts for different statuses
# context['active_count'] = AlertInstance.objects.filter(
# **tenant_filter, status='ACTIVE'
# ).count()
#
# context['acknowledged_count'] = AlertInstance.objects.filter(
# **tenant_filter, status='ACKNOWLEDGED'
# ).count()
#
# context['escalated_count'] = AlertInstance.objects.filter(
# **tenant_filter, status='ESCALATED'
# ).count()
#
# context['resolved_count'] = AlertInstance.objects.filter(
# **tenant_filter, status__in=['RESOLVED', 'AUTO_RESOLVED']
# ).count()
#
# return context
#
#
# class AlertDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# Detail view for alert instances.
# """
# model = AlertInstance
# template_name = 'communications/alert_detail.html'
# context_object_name = 'alert'
# permission_required = 'communications.view_alertinstance'
#
# def get_queryset(self):
# """Filter by tenant."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset.select_related(
# 'rule', 'acknowledged_by', 'resolved_by', 'related_message'
# )
#
# def get_context_data(self, **kwargs):
# """Add additional context."""
# context = super().get_context_data(**kwargs)
# alert = self.object
#
# # Add related alerts (same entity)
# context['related_alerts'] = AlertInstance.objects.filter(
# tenant=alert.tenant,
# entity_type=alert.entity_type,
# entity_id=alert.entity_id
# ).exclude(pk=alert.pk).order_by('-triggered_at')[:5]
#
# # Add form for updating status
# context['status_form'] = AlertInstanceForm(instance=alert, user=self.request.user)
#
# return context
#
#
# @login_required
# def acknowledge_alert(request, pk):
# """
# View to acknowledge an alert.
# """
# user = request.user
# tenant_filter = {}
#
# if hasattr(user, 'tenant') and user.tenant:
# tenant_filter['tenant'] = user.tenant
#
# alert = get_object_or_404(AlertInstance, pk=pk, **tenant_filter, status='ACTIVE')
#
# if request.method == 'POST':
# # Acknowledge the alert
# alert.acknowledge(request.user)
#
# # Log the action
# AuditLogger.log_action(
# user=request.user,
# action='ALERT_ACKNOWLEDGED',
# model='AlertInstance',
# object_id=str(alert.alert_id),
# details={
# 'title': alert.title,
# 'severity': alert.severity
# }
# )
#
# # Display success message
# messages.success(request, _("Alert acknowledged successfully."))
#
# # Redirect based on request type
# if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
# return JsonResponse({'status': 'success'})
#
# return redirect('communications:alert_detail', pk=alert.pk)
#
# # GET request to show confirmation page
# return render(request, 'communications/alert_acknowledge.html', {'alert': alert})
#
#
# @login_required
# def resolve_alert(request, pk):
# """
# View to resolve an alert.
# """
# user = request.user
# tenant_filter = {}
#
# if hasattr(user, 'tenant') and user.tenant:
# tenant_filter['tenant'] = user.tenant
#
# alert = get_object_or_404(
# AlertInstance,
# pk=pk,
# **tenant_filter,
# status__in=['ACTIVE', 'ACKNOWLEDGED', 'ESCALATED']
# )
#
# if request.method == 'POST':
# form = AlertInstanceForm(request.POST, instance=alert, user=request.user)
#
# if form.is_valid():
# form.save()
#
# # Log the action
# AuditLogger.log_action(
# user=request.user,
# action='ALERT_RESOLVED',
# model='AlertInstance',
# object_id=str(alert.alert_id),
# details={
# 'title': alert.title,
# 'severity': alert.severity,
# 'notes': form.cleaned_data.get('resolution_notes')
# }
# )
#
# # Display success message
# messages.success(request, _("Alert resolved successfully."))
#
# # Redirect based on request type
# if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
# return JsonResponse({'status': 'success'})
#
# return redirect('communications:alert_detail', pk=alert.pk)
#
# # Form is invalid
# if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
# return JsonResponse({'status': 'error', 'errors': form.errors}, status=400)
#
# # Render form with errors
# return render(request, 'communications/alert_resolve.html', {
# 'alert': alert,
# 'form': form
# })
#
# # GET request to show form
# form = AlertInstanceForm(instance=alert, user=request.user)
# return render(request, 'communications/alert_resolve.html', {
# 'alert': alert,
# 'form': form
# })
#
#
# class AlertRuleListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
# """
# List view for alert rules.
# """
# model = AlertRule
# template_name = 'communications/alert_rule_list.html'
# context_object_name = 'alert_rules'
# permission_required = 'communications.view_alertrule'
# paginate_by = 20
#
# def get_queryset(self):
# """Filter alert rules by tenant and search criteria."""
# queryset = AlertRule.objects.all()
# user = self.request.user
#
# # Filter by tenant
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# # Handle search
# search_query = self.request.GET.get('q')
# if search_query:
# queryset = queryset.filter(
# Q(name__icontains=search_query) |
# Q(description__icontains=search_query) |
# Q(entity_type__icontains=search_query)
# )
#
# # Handle condition type filter
# condition_type = self.request.GET.get('condition_type')
# if condition_type:
# queryset = queryset.filter(condition_type=condition_type)
#
# # Handle severity filter
# severity_filter = self.request.GET.get('severity')
# if severity_filter:
# queryset = queryset.filter(severity=severity_filter.upper())
#
# # Handle entity type filter
# entity_type = self.request.GET.get('entity_type')
# if entity_type:
# queryset = queryset.filter(entity_type=entity_type)
#
# # Handle active status filter
# active_filter = self.request.GET.get('active')
# if active_filter:
# is_active = (active_filter.lower() == 'true')
# queryset = queryset.filter(is_active=is_active)
#
# return queryset.select_related(
# 'template', 'created_by'
# ).prefetch_related(
# 'notification_channels', 'recipient_users'
# ).order_by('-created_at')
#
# def get_context_data(self, **kwargs):
# """Add filter options to context."""
# context = super().get_context_data(**kwargs)
# user = self.request.user
# tenant_filter = {}
#
# if hasattr(user, 'tenant') and user.tenant:
# tenant_filter['tenant'] = user.tenant
#
# # Add condition type choices
# context['condition_types'] = AlertRule.CONDITION_TYPE_CHOICES
#
# # Add severity choices
# context['severity_filters'] = AlertRule.SEVERITY_CHOICES
#
# # Add entity types (dynamically from data)
# entity_types = AlertRule.objects.filter(
# **tenant_filter
# ).values_list('entity_type', flat=True).distinct()
#
# context['entity_types'] = sorted(entity_types)
#
# # Add current filters to context
# context['current_filters'] = {
# 'q': self.request.GET.get('q', ''),
# 'condition_type': self.request.GET.get('condition_type', ''),
# 'severity': self.request.GET.get('severity', ''),
# 'entity_type': self.request.GET.get('entity_type', ''),
# 'active': self.request.GET.get('active', '')
# }
#
# return context
#
#
# class AlertRuleDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
# """
# Detail view for alert rules.
# """
# model = AlertRule
# template_name = 'communications/alert_rule_detail.html'
# context_object_name = 'rule'
# permission_required = 'communications.view_alertrule'
#
# def get_queryset(self):
# """Filter by tenant."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset.select_related(
# 'template', 'created_by'
# ).prefetch_related(
# 'notification_channels', 'recipient_users'
# )
#
# def get_context_data(self, **kwargs):
# """Add additional context."""
# context = super().get_context_data(**kwargs)
# rule = self.object
#
# # Get recent alerts from this rule
# context['recent_alerts'] = AlertInstance.objects.filter(
# rule=rule
# ).order_by('-triggered_at')[:10]
#
# # Get active alerts from this rule
# context['active_alerts'] = AlertInstance.objects.filter(
# rule=rule,
# status__in=['ACTIVE', 'ACKNOWLEDGED', 'ESCALATED']
# ).order_by('-triggered_at')
#
# # Alert statistics
# all_alerts = AlertInstance.objects.filter(rule=rule)
# total_count = all_alerts.count()
#
# if total_count > 0:
# # Status breakdown
# status_counts = {}
# for status, label in AlertInstance.STATUS_CHOICES:
# status_counts[status] = all_alerts.filter(status=status).count()
#
# # Resolution rate
# resolved_count = status_counts.get('RESOLVED', 0) + status_counts.get('AUTO_RESOLVED', 0)
# resolution_rate = (resolved_count / total_count) * 100 if total_count > 0 else 0
#
# context['alert_stats'] = {
# 'total': total_count,
# 'status_counts': status_counts,
# 'resolution_rate': resolution_rate
# }
#
# return context
#
#
# class AlertRuleCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
# """
# Create view for alert rules.
# """
# model = AlertRule
# form_class = AlertRuleForm
# template_name = 'communications/alert_rule_form.html'
# permission_required = 'communications.add_alertrule'
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def form_valid(self, form):
# """Handle valid form, create alert rule."""
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='ALERT_RULE_CREATED',
# model='AlertRule',
# object_id=str(self.object.rule_id),
# details={
# 'name': self.object.name,
# 'entity_type': self.object.entity_type,
# 'condition_type': self.object.condition_type,
# 'severity': self.object.severity
# }
# )
#
# # Display success message
# messages.success(self.request, _("Alert rule created successfully."))
#
# return response
#
# def get_success_url(self):
# """Return to rule detail view."""
# return reverse('communications:alert_rule_detail', args=[self.object.pk])
#
#
# class AlertRuleUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
# """
# Update view for alert rules.
# """
# model = AlertRule
# form_class = AlertRuleForm
# template_name = 'communications/alert_rule_form.html'
# permission_required = 'communications.change_alertrule'
#
# def get_queryset(self):
# """Filter by tenant."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset
#
# def get_form_kwargs(self):
# """Add user to form kwargs."""
# kwargs = super().get_form_kwargs()
# kwargs['user'] = self.request.user
# return kwargs
#
# def form_valid(self, form):
# """Handle valid form, update alert rule."""
# response = super().form_valid(form)
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='ALERT_RULE_UPDATED',
# model='AlertRule',
# object_id=str(self.object.rule_id),
# details={
# 'name': self.object.name,
# 'entity_type': self.object.entity_type,
# 'condition_type': self.object.condition_type,
# 'severity': self.object.severity
# }
# )
#
# # Display success message
# messages.success(self.request, _("Alert rule updated successfully."))
#
# return response
#
# def get_success_url(self):
# """Return to rule detail view."""
# return reverse('communications:alert_rule_detail', args=[self.object.pk])
#
#
# class AlertRuleDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
# """
# Delete view for alert rules.
# """
# model = AlertRule
# template_name = 'communications/alert_rule_confirm_delete.html'
# context_object_name = 'rule'
# permission_required = 'communications.delete_alertrule'
# success_url = reverse_lazy('communications:alert_rule_list')
#
# def get_queryset(self):
# """Filter by tenant."""
# queryset = super().get_queryset()
# user = self.request.user
#
# if hasattr(user, 'tenant') and user.tenant:
# queryset = queryset.filter(tenant=user.tenant)
#
# return queryset
#
# def delete(self, request, *args, **kwargs):
# """Handle delete request, log action."""
# rule = self.get_object()
#
# # Check for active alerts
# active_alerts = AlertInstance.objects.filter(
# rule=rule,
# status__in=['ACTIVE', 'ACKNOWLEDGED', 'ESCALATED']
# ).count()
#
# if active_alerts > 0:
# messages.warning(
# self.request,
# _("Alert rule deleted, but note that there are still {count} active alerts from this rule.").format(
# count=active_alerts
# )
# )
#
# # Log the action
# AuditLogger.log_action(
# user=self.request.user,
# action='ALERT_RULE_DELETED',
# model='AlertRule',
# object_id=str(rule.rule_id),
# details={
# 'name': rule.name,
# 'entity_type': rule.entity_type,
# 'condition_type': rule.condition_type,
# 'severity': rule.severity
# }
# )
#
# # Display success message
# messages.success(self.request, _("Alert rule deleted successfully."))
#
# return super().delete(request, *args, **kwargs)
#
#
# @login_required
# def send_message(request):
# """
# View for quickly sending a message from a template.
# """
# if request.method == 'POST':
# form = SendMessageForm(request.POST, user=request.user)
#
# if form.is_valid():
# template = form.cleaned_data['template']
# recipients = form.cleaned_data['recipients']
# variables = form.cleaned_data['variables']
# priority = form.cleaned_data['priority']
#
# # Render the template
# rendered = template.render(variables)
#
# # Create the message
# message = Message.objects.create(
# tenant=getattr(request.user, 'tenant', None),
# sender=request.user,
# subject=rendered.get('subject'),
# body=rendered.get('body'),
# html_body=rendered.get('html'),
# message_type=template.template_type,
# priority=priority,
# template=template,
# sent_at=timezone.now()
# )
#
# # Add recipients
# for recipient in recipients:
# MessageRecipient.objects.create(
# message=message,
# recipient=recipient,
# tenant=getattr(request.user, 'tenant', None),
# channel=template.default_channel,
# status='SENT',
# sent_at=timezone.now()
# )
#
# # Log the action
# AuditLogger.log_action(
# user=request.user,
# action='MESSAGE_SENT',
# model='Message',
# object_id=str(message.message_id),
# details={
# 'template': template.name,
# 'recipient_count': len(recipients),
# 'message_type': template.template_type
# }
# )
#
# # Display success message
# messages.success(
# request,
# _("Message sent to {count} recipients.").format(count=len(recipients))
# )
#
# # Redirect
# return redirect('communications:message_detail', pk=message.pk)
# else:
# # GET request, create empty form
# form = SendMessageForm(user=request.user)
#
# # Show form
# return render(request, 'communications/send_message.html', {'form': form})
#
#
# @login_required
# def communications_stats(request):
# """
# Return communications statistics for dashboard updates.
# """
# today = timezone.now().date()
# tenant_filter = {}
#
# if hasattr(request.user, 'tenant') and request.user.tenant:
# tenant_filter['tenant'] = request.user.tenant
#
# context = {
# 'total_messages': Message.objects.filter(**tenant_filter).count(),
# 'total_templates': NotificationTemplate.objects.filter(**tenant_filter).count(),
# 'total_channels': CommunicationChannel.objects.filter(
# **tenant_filter,
# is_active=True
# ).count(),
# 'total_alert_rules': AlertRule.objects.filter(**tenant_filter).count(),
# 'messages_today': Message.objects.filter(
# **tenant_filter,
# created_at__date=today
# ).count(),
# 'successful_deliveries': DeliveryLog.objects.filter(
# **tenant_filter,
# delivery_time__date=today,
# status='DELIVERED'
# ).count(),
# 'active_alerts': AlertInstance.objects.filter(
# **tenant_filter,
# status='ACTIVE'
# ).count(),
# }
#
# return render(request, 'communications/partials/communications_stats.html', context)
#
#
# class CommunicationsStatsViewSet(viewsets.ViewSet):
# """ViewSet for communications statistics"""
# permission_classes = [permissions.IsAuthenticated]
#
# @action(detail=False, methods=['get'])
# def dashboard(self, request):
# """Get communications dashboard statistics"""
# tenant_filter = {}
# if hasattr(request.user, 'tenant') and request.user.tenant:
# tenant_filter['tenant'] = request.user.tenant
#
# today = timezone.now().date()
#
# # Message statistics
# messages = Message.objects.filter(**tenant_filter)
# total_messages = messages.count()
# messages_today = messages.filter(created_at__date=today).count()
# pending_messages = messages.filter(
# is_draft=False,
# sent_at__isnull=True
# ).count()
#
# # Delivery statistics
# recipients = MessageRecipient.objects.filter(**tenant_filter)
# delivered_messages = recipients.filter(status='DELIVERED').count()
# failed_messages = recipients.filter(status='FAILED').count()
#
# # Alert statistics
# alerts = AlertInstance.objects.filter(**tenant_filter)
# active_alerts = alerts.filter(status='ACTIVE').count()
#
# # Delivery rate
# total_sent = recipients.filter(status__in=['DELIVERED', 'FAILED']).count()
# delivery_rate = (delivered_messages / total_sent * 100) if total_sent > 0 else 0
#
# # Message types breakdown
# message_types = messages.values('message_type').annotate(
# count=Count('id')
# ).order_by('-count')
#
# # Channel usage
# channels = CommunicationChannel.objects.filter(**tenant_filter, is_active=True)
# channel_usage = {}
# for channel in channels:
# # Get usage data
# usage_count = DeliveryLog.objects.filter(
# channel=channel,
# last_attempt_at__date=today
# ).count()
# channel_usage[channel.name] = usage_count
#
# stats = {
# 'total_messages': total_messages,
# 'messages_today': messages_today,
# 'pending_messages': pending_messages,
# 'delivered_messages': delivered_messages,
# 'failed_messages': failed_messages,
# 'active_alerts': active_alerts,
# 'delivery_rate': round(delivery_rate, 1),
# 'message_types': {item['message_type']: item['count'] for item in message_types},
# 'channel_usage': channel_usage
# }
#
# serializer = CommunicationsStatsSerializer(stats)
# return Response(serializer.data)
#
# @action(detail=False, methods=['post'])
# def send_notification(self, request):
# """Send notification using template"""
# serializer = NotificationSendSerializer(data=request.data)
#
# if serializer.is_valid():
# template = NotificationTemplate.objects.get(
# id=serializer.validated_data['template_id']
# )
# recipients = User.objects.filter(
# id__in=serializer.validated_data['recipients']
# )
# variables = serializer.validated_data.get('variables', {})
#
# # Create message using template
# subject = template.subject_template.format(**variables) if variables else template.subject_template
# body = template.body_template.format(**variables) if variables else template.body_template
#
# message = Message.objects.create(
# sender=request.user,
# subject=subject,
# body=body,
# message_type=template.template_type,
# priority='NORMAL',
# sent_at=timezone.now(),
# tenant=getattr(request.user, 'tenant', None)
# )
#
# # Create recipients
# for recipient in recipients:
# MessageRecipient.objects.create(
# message=message,
# recipient=recipient,
# status='SENT',
# delivered_at=timezone.now(),
# tenant=getattr(request.user, 'tenant', None)
# )
#
# # Log the action
# AuditLogger.log_action(
# user=request.user,
# action='NOTIFICATION_SENT',
# model='Message',
# object_id=str(message.message_id),
# details={
# 'template_name': template.name,
# 'recipient_count': len(recipients)
# }
# )
#
# return Response({
# 'message': 'Notification sent successfully',
# 'recipient_count': len(recipients),
# 'message_data': MessageSerializer(message).data
# })
#
# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#