2748 lines
96 KiB
Python
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)
|
|
#
|