3801 lines
126 KiB
Python
3801 lines
126 KiB
Python
"""
|
|
Core app views for hospital management system with comprehensive CRUD operations.
|
|
"""
|
|
|
|
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, PermissionRequiredMixin
|
|
from django.views.generic import (
|
|
TemplateView, ListView, DetailView, CreateView, UpdateView, DeleteView
|
|
)
|
|
from django.http import JsonResponse
|
|
from django.db.models import Count, Q
|
|
from django.utils import timezone
|
|
from django.contrib import messages
|
|
from django.urls import reverse_lazy, reverse
|
|
from accounts.models import User
|
|
from datetime import timedelta
|
|
from .models import (
|
|
Tenant, AuditLogEntry, SystemConfiguration, SystemNotification,
|
|
IntegrationLog
|
|
)
|
|
from hr.models import Department
|
|
from hr.forms import DepartmentForm
|
|
|
|
# Create aliases for models to match the views
|
|
AuditLog = AuditLogEntry
|
|
|
|
from .forms import (
|
|
TenantForm, SystemConfigurationForm, SystemNotificationForm,CoreSearchForm
|
|
)
|
|
from .utils import AuditLogger
|
|
|
|
|
|
# ============================================================================
|
|
# DASHBOARD AND OVERVIEW VIEWS
|
|
# ============================================================================
|
|
|
|
class DashboardView(LoginRequiredMixin, TemplateView):
|
|
"""
|
|
Main dashboard view.
|
|
"""
|
|
template_name = 'core/dashboard.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
tenant = self.request.user.tenant
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
if tenant:
|
|
# Get dashboard statistics
|
|
context.update({
|
|
'tenant': tenant,
|
|
'recent_audit_logs': AuditLogEntry.objects.filter(
|
|
tenant=tenant
|
|
).order_by('-timestamp')[:10],
|
|
'active_notifications': SystemNotification.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None),
|
|
is_active=True,
|
|
start_date__lte=timezone.now(),
|
|
end_date__gte=timezone.now()
|
|
).order_by('-priority', '-created_at')[:5],
|
|
'total_departments': Department.objects.filter(tenant=tenant).count(),
|
|
'total_configurations': SystemConfiguration.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None)
|
|
).count(),
|
|
})
|
|
|
|
return context
|
|
|
|
|
|
class TenantListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
|
"""
|
|
List all tenants (Super admin only).
|
|
"""
|
|
model = Tenant
|
|
template_name = 'core/tenants/tenant_list.html'
|
|
context_object_name = 'tenants'
|
|
paginate_by = 20
|
|
permission_required = 'core.view_tenant'
|
|
|
|
def get_queryset(self):
|
|
queryset = Tenant.objects.all().order_by('name')
|
|
|
|
# Apply search filter
|
|
search = self.request.GET.get('search')
|
|
if search:
|
|
queryset = queryset.filter(
|
|
Q(name__icontains=search) |
|
|
Q(domain__icontains=search) |
|
|
Q(contact_email__icontains=search)
|
|
)
|
|
|
|
# Apply status filter
|
|
status = self.request.GET.get('status')
|
|
if status:
|
|
queryset = queryset.filter(is_active=(status == 'active'))
|
|
|
|
return queryset
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['search_form'] = CoreSearchForm(self.request.GET)
|
|
return context
|
|
|
|
|
|
class TenantDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
|
"""
|
|
Display tenant details.
|
|
"""
|
|
model = Tenant
|
|
template_name = 'core/tenants/tenant_detail.html'
|
|
context_object_name = 'tenant'
|
|
permission_required = 'core.view_tenant'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
tenant = self.object
|
|
|
|
# Get tenant statistics
|
|
context.update({
|
|
'user_count': tenant.get_user_count(),
|
|
'patient_count': tenant.get_patient_count(),
|
|
'recent_audit_logs': AuditLogEntry.objects.filter(
|
|
tenant=tenant
|
|
).order_by('-timestamp')[:10],
|
|
'departments': Department.objects.filter(tenant=tenant).order_by('name'),
|
|
'configurations': SystemConfiguration.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None)
|
|
).order_by('category', 'key'),
|
|
})
|
|
|
|
return context
|
|
|
|
|
|
class TenantCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
|
"""
|
|
Create new tenant.
|
|
"""
|
|
model = Tenant
|
|
form_class = TenantForm
|
|
template_name = 'core/tenants/tenant_form.html'
|
|
permission_required = 'core.add_tenant'
|
|
success_url = reverse_lazy('core:tenant_list')
|
|
|
|
def form_valid(self, form):
|
|
response = super().form_valid(form)
|
|
|
|
# Log tenant creation
|
|
AuditLogger.log_event(
|
|
tenant=None, # System level event
|
|
event_type='CREATE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Create Tenant',
|
|
description=f'Created new tenant: {self.object.name}',
|
|
user=self.request.user,
|
|
content_object=self.object,
|
|
request=self.request
|
|
)
|
|
|
|
messages.success(self.request, f'Tenant "{self.object.name}" created successfully.')
|
|
return response
|
|
|
|
|
|
class TenantUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
|
"""
|
|
Update tenant information.
|
|
"""
|
|
model = Tenant
|
|
form_class = TenantForm
|
|
template_name = 'core/tenants/tenant_form.html'
|
|
permission_required = 'core.change_tenant'
|
|
|
|
def get_success_url(self):
|
|
return reverse('core:tenant_detail', kwargs={'pk': self.object.pk})
|
|
|
|
def form_valid(self, form):
|
|
response = super().form_valid(form)
|
|
|
|
# Log tenant update
|
|
AuditLogger.log_event(
|
|
tenant=self.object,
|
|
event_type='UPDATE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Update Tenant',
|
|
description=f'Updated tenant: {self.object.name}',
|
|
user=self.request.user,
|
|
content_object=self.object,
|
|
request=self.request
|
|
)
|
|
|
|
messages.success(self.request, f'Tenant "{self.object.name}" updated successfully.')
|
|
return response
|
|
|
|
|
|
class TenantDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
|
|
"""
|
|
Delete tenant (soft delete to inactive).
|
|
"""
|
|
model = Tenant
|
|
template_name = 'core/tenants/tenant_confirm_delete.html'
|
|
permission_required = 'core.delete_tenant'
|
|
success_url = reverse_lazy('core:tenant_list')
|
|
|
|
def delete(self, request, *args, **kwargs):
|
|
self.object = self.get_object()
|
|
|
|
# Soft delete - set to inactive
|
|
self.object.is_active = False
|
|
self.object.save()
|
|
|
|
# Log tenant deletion
|
|
AuditLogger.log_event(
|
|
tenant=self.object,
|
|
event_type='DELETE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Deactivate Tenant',
|
|
description=f'Deactivated tenant: {self.object.name}',
|
|
user=request.user,
|
|
content_object=self.object,
|
|
request=request
|
|
)
|
|
|
|
messages.success(request, f'Tenant "{self.object.name}" deactivated successfully.')
|
|
return redirect(self.success_url)
|
|
|
|
|
|
class AuditLogListView(LoginRequiredMixin, ListView):
|
|
"""
|
|
Audit log listing view.
|
|
"""
|
|
model = AuditLogEntry
|
|
template_name = 'core/audit_logs/audit_log.html'
|
|
context_object_name = 'audit_logs'
|
|
paginate_by = 50
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
if not tenant:
|
|
return AuditLogEntry.objects.none()
|
|
|
|
queryset = AuditLogEntry.objects.filter(tenant=tenant)
|
|
|
|
# Apply filters
|
|
event_type = self.request.GET.get('event_type')
|
|
if event_type:
|
|
queryset = queryset.filter(event_type=event_type)
|
|
|
|
event_category = self.request.GET.get('event_category')
|
|
if event_category:
|
|
queryset = queryset.filter(event_category=event_category)
|
|
|
|
user_id = self.request.GET.get('user_id')
|
|
if user_id:
|
|
queryset = queryset.filter(user_id=user_id)
|
|
|
|
date_from = self.request.GET.get('date_from')
|
|
if date_from:
|
|
queryset = queryset.filter(timestamp__gte=date_from)
|
|
|
|
date_to = self.request.GET.get('date_to')
|
|
if date_to:
|
|
queryset = queryset.filter(timestamp__lte=date_to)
|
|
|
|
return queryset.order_by('-timestamp')
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
tenant = self.request.user.tenant
|
|
|
|
if tenant:
|
|
# Get filter options
|
|
context.update({
|
|
'event_types': AuditLogEntry.objects.filter(
|
|
tenant=tenant
|
|
).values_list('event_type', flat=True).distinct(),
|
|
'event_categories': AuditLogEntry.objects.filter(
|
|
tenant=tenant
|
|
).values_list('event_category', flat=True).distinct(),
|
|
})
|
|
|
|
return context
|
|
|
|
|
|
class AuditLogDetailView(LoginRequiredMixin, DetailView):
|
|
"""
|
|
Display detailed audit log entry.
|
|
"""
|
|
model = AuditLogEntry
|
|
template_name = 'core/audit_logs/audit_log_detail.html'
|
|
context_object_name = 'audit_log'
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
if not tenant:
|
|
return AuditLogEntry.objects.none()
|
|
return AuditLogEntry.objects.filter(tenant=tenant)
|
|
|
|
|
|
class SystemConfigurationListView(LoginRequiredMixin, ListView):
|
|
"""
|
|
System configuration view.
|
|
"""
|
|
model = SystemConfiguration
|
|
template_name = 'core/configurations/system_configuration.html'
|
|
context_object_name = 'configurations'
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
queryset = SystemConfiguration.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None),
|
|
is_active=True
|
|
).order_by('category', 'key')
|
|
|
|
# Apply search filter
|
|
search = self.request.GET.get('search')
|
|
if search:
|
|
queryset = queryset.filter(
|
|
Q(key__icontains=search) |
|
|
Q(description__icontains=search) |
|
|
Q(category__icontains=search)
|
|
)
|
|
|
|
# Apply category filter
|
|
category = self.request.GET.get('category')
|
|
if category:
|
|
queryset = queryset.filter(category=category)
|
|
|
|
return queryset
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
tenant = self.request.user.tenant
|
|
|
|
if tenant:
|
|
# Group configurations by category
|
|
configurations = context['configurations']
|
|
grouped_configs = {}
|
|
for config in configurations:
|
|
category = config.category
|
|
if category not in grouped_configs:
|
|
grouped_configs[category] = []
|
|
grouped_configs[category].append(config)
|
|
|
|
context['grouped_configurations'] = grouped_configs
|
|
|
|
# Get categories for filter
|
|
context['categories'] = SystemConfiguration.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None)
|
|
).values_list('category', flat=True).distinct()
|
|
|
|
return context
|
|
|
|
|
|
class SystemConfigurationDetailView(LoginRequiredMixin, DetailView):
|
|
"""
|
|
Display system configuration details.
|
|
"""
|
|
model = SystemConfiguration
|
|
template_name = 'core/configurations/system_configuration_detail.html'
|
|
context_object_name = 'configuration'
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
return SystemConfiguration.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None)
|
|
)
|
|
|
|
|
|
class SystemConfigurationCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
|
"""
|
|
Create new system configuration.
|
|
"""
|
|
model = SystemConfiguration
|
|
form_class = SystemConfigurationForm
|
|
template_name = 'core/configurations/system_configuration_form.html'
|
|
permission_required = 'core.add_systemconfiguration'
|
|
success_url = reverse_lazy('core:system_configuration_list')
|
|
|
|
def form_valid(self, form):
|
|
# Set tenant
|
|
form.instance.tenant = self.request.user.tenant
|
|
response = super().form_valid(form)
|
|
|
|
# Log configuration creation
|
|
AuditLogger.log_event(
|
|
tenant=form.instance.tenant,
|
|
event_type='CREATE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Create Configuration',
|
|
description=f'Created configuration: {self.object.key}',
|
|
user=self.request.user,
|
|
content_object=self.object,
|
|
request=self.request
|
|
)
|
|
|
|
messages.success(self.request, f'Configuration "{self.object.key}" created successfully.')
|
|
return response
|
|
|
|
|
|
class SystemConfigurationUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
|
"""
|
|
Update system configuration.
|
|
"""
|
|
model = SystemConfiguration
|
|
form_class = SystemConfigurationForm
|
|
template_name = 'core/configurations/system_configuration_form.html'
|
|
permission_required = 'core.change_systemconfiguration'
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
return SystemConfiguration.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None)
|
|
)
|
|
|
|
def get_success_url(self):
|
|
return reverse('core:system_configuration_detail', kwargs={'pk': self.object.pk})
|
|
|
|
def form_valid(self, form):
|
|
response = super().form_valid(form)
|
|
|
|
# Log configuration update
|
|
AuditLogger.log_event(
|
|
tenant=self.object.tenant,
|
|
event_type='UPDATE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Update Configuration',
|
|
description=f'Updated configuration: {self.object.key}',
|
|
user=self.request.user,
|
|
content_object=self.object,
|
|
request=self.request
|
|
)
|
|
|
|
messages.success(self.request, f'Configuration "{self.object.key}" updated successfully.')
|
|
return response
|
|
|
|
|
|
class SystemConfigurationDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
|
|
"""
|
|
Delete system configuration.
|
|
"""
|
|
model = SystemConfiguration
|
|
template_name = 'core/configurations/system_configuration_confirm_delete.html'
|
|
permission_required = 'core.delete_systemconfiguration'
|
|
success_url = reverse_lazy('core:system_configuration_list')
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
return SystemConfiguration.objects.filter(tenant=tenant) # Only tenant-specific configs can be deleted
|
|
|
|
def delete(self, request, *args, **kwargs):
|
|
self.object = self.get_object()
|
|
|
|
# Log configuration deletion
|
|
AuditLogger.log_event(
|
|
tenant=self.object.tenant,
|
|
event_type='DELETE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Delete Configuration',
|
|
description=f'Deleted configuration: {self.object.key}',
|
|
user=request.user,
|
|
content_object=self.object,
|
|
request=request
|
|
)
|
|
|
|
messages.success(request, f'Configuration "{self.object.key}" deleted successfully.')
|
|
return super().delete(request, *args, **kwargs)
|
|
|
|
|
|
class SystemNotificationListView(LoginRequiredMixin, ListView):
|
|
"""
|
|
List system notifications.
|
|
"""
|
|
model = SystemNotification
|
|
template_name = 'core/notifications/notification_list.html'
|
|
context_object_name = 'notifications'
|
|
paginate_by = 20
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
queryset = SystemNotification.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None)
|
|
).order_by('-created_at')
|
|
|
|
# Apply filters
|
|
status = self.request.GET.get('status')
|
|
if status == 'active':
|
|
queryset = queryset.filter(is_active=True)
|
|
elif status == 'inactive':
|
|
queryset = queryset.filter(is_active=False)
|
|
|
|
priority = self.request.GET.get('priority')
|
|
if priority:
|
|
queryset = queryset.filter(priority=priority)
|
|
|
|
search = self.request.GET.get('search')
|
|
if search:
|
|
queryset = queryset.filter(
|
|
Q(title__icontains=search) |
|
|
Q(message__icontains=search)
|
|
)
|
|
|
|
return queryset
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['priority_choices'] = SystemNotification.PRIORITY_CHOICES
|
|
return context
|
|
|
|
|
|
class SystemNotificationDetailView(LoginRequiredMixin, DetailView):
|
|
"""
|
|
Display notification details.
|
|
"""
|
|
model = SystemNotification
|
|
template_name = 'core/notifications/notification_detail.html'
|
|
context_object_name = 'notification'
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
return SystemNotification.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None)
|
|
)
|
|
|
|
|
|
class SystemNotificationCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
|
"""
|
|
Create new system notification.
|
|
"""
|
|
model = SystemNotification
|
|
form_class = SystemNotificationForm
|
|
template_name = 'core/notifications/notification_form.html'
|
|
permission_required = 'core.add_systemnotification'
|
|
success_url = reverse_lazy('core:notification_list')
|
|
|
|
def form_valid(self, form):
|
|
# Set tenant and creator
|
|
form.instance.tenant = self.request.user.tenant
|
|
form.instance.created_by = self.request.user
|
|
response = super().form_valid(form)
|
|
|
|
# Log notification creation
|
|
AuditLogger.log_event(
|
|
tenant=form.instance.tenant,
|
|
event_type='CREATE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Create Notification',
|
|
description=f'Created notification: {self.object.title}',
|
|
user=self.request.user,
|
|
content_object=self.object,
|
|
request=self.request
|
|
)
|
|
|
|
messages.success(self.request, f'Notification "{self.object.title}" created successfully.')
|
|
return response
|
|
|
|
|
|
class SystemNotificationUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
|
"""
|
|
Update system notification.
|
|
"""
|
|
model = SystemNotification
|
|
form_class = SystemNotificationForm
|
|
template_name = 'core/notifications/notification_form.html'
|
|
permission_required = 'core.change_systemnotification'
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
return SystemNotification.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None)
|
|
)
|
|
|
|
def get_success_url(self):
|
|
return reverse('core:notification_detail', kwargs={'pk': self.object.pk})
|
|
|
|
def form_valid(self, form):
|
|
response = super().form_valid(form)
|
|
|
|
# Log notification update
|
|
AuditLogger.log_event(
|
|
tenant=self.object.tenant,
|
|
event_type='UPDATE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Update Notification',
|
|
description=f'Updated notification: {self.object.title}',
|
|
user=self.request.user,
|
|
content_object=self.object,
|
|
request=self.request
|
|
)
|
|
|
|
messages.success(self.request, f'Notification "{self.object.title}" updated successfully.')
|
|
return response
|
|
|
|
|
|
class SystemNotificationDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
|
|
"""
|
|
Delete system notification.
|
|
"""
|
|
model = SystemNotification
|
|
template_name = 'core/notifications/notification_confirm_delete.html'
|
|
permission_required = 'core.delete_systemnotification'
|
|
success_url = reverse_lazy('core:notification_list')
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
return SystemNotification.objects.filter(tenant=tenant) # Only tenant notifications can be deleted
|
|
|
|
def delete(self, request, *args, **kwargs):
|
|
self.object = self.get_object()
|
|
|
|
# Log notification deletion
|
|
AuditLogger.log_event(
|
|
tenant=self.object.tenant,
|
|
event_type='DELETE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Delete Notification',
|
|
description=f'Deleted notification: {self.object.title}',
|
|
user=request.user,
|
|
content_object=self.object,
|
|
request=request
|
|
)
|
|
|
|
messages.success(request, f'Notification "{self.object.title}" deleted successfully.')
|
|
return super().delete(request, *args, **kwargs)
|
|
|
|
|
|
class IntegrationLogListView(LoginRequiredMixin, ListView):
|
|
"""
|
|
List integration logs.
|
|
"""
|
|
model = IntegrationLog
|
|
template_name = 'core/integration_logs/integration_log_list.html'
|
|
context_object_name = 'logs'
|
|
paginate_by = 50
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
if not tenant:
|
|
return IntegrationLog.objects.none()
|
|
|
|
queryset = IntegrationLog.objects.filter(tenant=tenant).order_by('-timestamp')
|
|
|
|
# Apply filters
|
|
log_level = self.request.GET.get('log_level')
|
|
if log_level:
|
|
queryset = queryset.filter(log_level=log_level)
|
|
|
|
component = self.request.GET.get('component')
|
|
if component:
|
|
queryset = queryset.filter(component__icontains=component)
|
|
|
|
date_from = self.request.GET.get('date_from')
|
|
if date_from:
|
|
queryset = queryset.filter(timestamp__gte=date_from)
|
|
|
|
date_to = self.request.GET.get('date_to')
|
|
if date_to:
|
|
queryset = queryset.filter(timestamp__lte=date_to)
|
|
|
|
return queryset
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
tenant = self.request.user.tenant
|
|
|
|
if tenant:
|
|
context.update({
|
|
'log_levels': IntegrationLog.objects.filter(
|
|
tenant=tenant
|
|
).values_list('log_level', flat=True).distinct(),
|
|
'components': IntegrationLog.objects.filter(
|
|
tenant=tenant
|
|
).values_list('component', flat=True).distinct(),
|
|
})
|
|
|
|
return context
|
|
|
|
|
|
class IntegrationLogDetailView(LoginRequiredMixin, DetailView):
|
|
"""
|
|
Display integration log details.
|
|
"""
|
|
model = IntegrationLog
|
|
template_name = 'core/integration_logs/integration_log_detail.html'
|
|
context_object_name = 'log'
|
|
|
|
def get_queryset(self):
|
|
tenant = self.request.user.tenant
|
|
if not tenant:
|
|
return IntegrationLog.objects.none()
|
|
return IntegrationLog.objects.filter(tenant=tenant)
|
|
|
|
|
|
@login_required
|
|
def dashboard_stats(request):
|
|
"""
|
|
HTMX view for dashboard statistics.
|
|
"""
|
|
tenant = request.user.tenant
|
|
if not tenant:
|
|
return JsonResponse({'error': 'No tenant found'}, status=400)
|
|
|
|
# Calculate statistics
|
|
now = timezone.now()
|
|
today = now.date()
|
|
week_ago = now - timedelta(days=7)
|
|
|
|
stats = {
|
|
'total_users': tenant.get_user_count(),
|
|
'total_patients': tenant.get_patient_count(),
|
|
'total_departments': Department.objects.filter(tenant=tenant, is_active=True).count(),
|
|
'audit_logs_today': AuditLogEntry.objects.filter(
|
|
tenant=tenant,
|
|
timestamp__date=today
|
|
).count(),
|
|
'audit_logs_week': AuditLogEntry.objects.filter(
|
|
tenant=tenant,
|
|
timestamp__gte=week_ago
|
|
).count(),
|
|
'active_notifications': SystemNotification.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None),
|
|
is_active=True,
|
|
start_date__lte=now,
|
|
end_date__gte=now
|
|
).count(),
|
|
'total_configurations': SystemConfiguration.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None),
|
|
is_active=True
|
|
).count(),
|
|
}
|
|
|
|
return render(request, 'core/partials/dashboard_stats.html', {'stats': stats})
|
|
|
|
|
|
@login_required
|
|
def audit_log_search(request):
|
|
"""
|
|
HTMX view for audit log search.
|
|
"""
|
|
tenant = request.user.tenant
|
|
if not tenant:
|
|
return JsonResponse({'error': 'No tenant found'}, status=400)
|
|
|
|
search_query = request.GET.get('search', '')
|
|
queryset = AuditLogEntry.objects.filter(tenant=tenant)
|
|
|
|
if search_query:
|
|
queryset = queryset.filter(
|
|
Q(action__icontains=search_query) |
|
|
Q(description__icontains=search_query) |
|
|
Q(user_email__icontains=search_query) |
|
|
Q(object_repr__icontains=search_query)
|
|
)
|
|
|
|
audit_logs = queryset.order_by('-timestamp')[:20]
|
|
|
|
return render(request, 'core/partials/audit_log_list.html', {
|
|
'audit_logs': audit_logs
|
|
})
|
|
|
|
|
|
@login_required
|
|
def system_notifications(request):
|
|
"""
|
|
HTMX view for system notifications.
|
|
"""
|
|
tenant = request.user.tenant
|
|
if not tenant:
|
|
return JsonResponse({'error': 'No tenant found'}, status=400)
|
|
|
|
notifications = SystemNotification.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None),
|
|
is_active=True
|
|
).filter(
|
|
start_date__lte=timezone.now()
|
|
).filter(
|
|
Q(end_date__gte=timezone.now()) | Q(end_date=None)
|
|
).order_by('-priority', '-created_at')
|
|
|
|
return render(request, 'core/partials/system_notifications.html', {
|
|
'notifications': notifications
|
|
})
|
|
|
|
|
|
@login_required
|
|
def dismiss_notification(request, notification_id):
|
|
"""
|
|
HTMX view to dismiss a notification.
|
|
"""
|
|
tenant = request.user.tenant
|
|
if not tenant:
|
|
return JsonResponse({'error': 'No tenant found'}, status=400)
|
|
|
|
notification = get_object_or_404(
|
|
SystemNotification,
|
|
notification_id=notification_id,
|
|
is_dismissible=True
|
|
)
|
|
|
|
# Log the dismissal
|
|
AuditLogger.log_event(
|
|
tenant=tenant,
|
|
event_type='UPDATE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Dismiss Notification',
|
|
description=f'User dismissed notification: {notification.title}',
|
|
user=request.user,
|
|
content_object=notification,
|
|
request=request
|
|
)
|
|
|
|
return JsonResponse({'status': 'dismissed'})
|
|
|
|
|
|
@login_required
|
|
def tenant_info(request):
|
|
"""
|
|
HTMX view for tenant information.
|
|
"""
|
|
tenant = request.user.tenant
|
|
if not tenant:
|
|
return JsonResponse({'error': 'No tenant found'}, status=400)
|
|
|
|
return render(request, 'core/partials/tenant_info.html', {
|
|
'tenant': tenant
|
|
})
|
|
|
|
|
|
@login_required
|
|
def system_health(request):
|
|
"""
|
|
HTMX view for system health status.
|
|
"""
|
|
tenant = request.user.tenant
|
|
if not tenant:
|
|
return JsonResponse({'error': 'No tenant found'}, status=400)
|
|
|
|
# Calculate system health metrics
|
|
now = timezone.now()
|
|
hour_ago = now - timedelta(hours=1)
|
|
|
|
health_data = {
|
|
'database_status': 'healthy', # Would check actual database health
|
|
'cache_status': 'healthy', # Would check cache health
|
|
'recent_errors': AuditLogEntry.objects.filter(
|
|
tenant=tenant,
|
|
event_type='ERROR',
|
|
timestamp__gte=hour_ago
|
|
).count(),
|
|
'system_load': 'normal', # Would check actual system load
|
|
'last_updated': now.strftime('%Y-%m-%d %H:%M:%S'),
|
|
'active_departments': Department.objects.filter(
|
|
tenant=tenant,
|
|
is_active=True
|
|
).count(),
|
|
'total_configurations': SystemConfiguration.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant=None),
|
|
is_active=True
|
|
).count(),
|
|
}
|
|
|
|
return render(request, 'core/partials/system_health.html', {
|
|
'health_data': health_data
|
|
})
|
|
|
|
|
|
@login_required
|
|
def activate_notification(request, pk):
|
|
"""
|
|
Activate a system notification.
|
|
"""
|
|
tenant = request.user.tenant
|
|
if not tenant:
|
|
messages.error(request, 'No tenant found.')
|
|
return redirect('core:notification_list')
|
|
|
|
notification = get_object_or_404(
|
|
SystemNotification,
|
|
pk=pk,
|
|
tenant=tenant
|
|
)
|
|
|
|
notification.is_active = True
|
|
notification.save()
|
|
|
|
# Log activation
|
|
AuditLogger.log_event(
|
|
tenant=tenant,
|
|
event_type='UPDATE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Activate Notification',
|
|
description=f'Activated notification: {notification.title}',
|
|
user=request.user,
|
|
content_object=notification,
|
|
request=request
|
|
)
|
|
|
|
messages.success(request, f'Notification "{notification.title}" activated successfully.')
|
|
return redirect('core:system_notification_detail', pk=pk)
|
|
|
|
|
|
@login_required
|
|
def deactivate_notification(request, pk):
|
|
"""
|
|
Deactivate a system notification.
|
|
"""
|
|
tenant = request.user.tenant
|
|
if not tenant:
|
|
messages.error(request, 'No tenant found.')
|
|
return redirect('core:notification_list')
|
|
|
|
notification = get_object_or_404(
|
|
SystemNotification,
|
|
pk=pk,
|
|
tenant=tenant
|
|
)
|
|
|
|
notification.is_active = False
|
|
notification.save()
|
|
|
|
# Log deactivation
|
|
AuditLogger.log_event(
|
|
tenant=tenant,
|
|
event_type='UPDATE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Deactivate Notification',
|
|
description=f'Deactivated notification: {notification.title}',
|
|
user=request.user,
|
|
content_object=notification,
|
|
request=request
|
|
)
|
|
|
|
messages.success(request, f'Notification "{notification.title}" deactivated successfully.')
|
|
return redirect('core:system_notification_detail', pk=pk)
|
|
|
|
|
|
@login_required
|
|
def reset_configuration(request, pk):
|
|
"""
|
|
Reset configuration to default value.
|
|
"""
|
|
tenant = request.user.tenant
|
|
if not tenant:
|
|
messages.error(request, 'No tenant found.')
|
|
return redirect('core:system_configuration_list')
|
|
|
|
configuration = get_object_or_404(
|
|
SystemConfiguration,
|
|
pk=pk,
|
|
tenant=tenant
|
|
)
|
|
|
|
# Reset to default value
|
|
old_value = configuration.value
|
|
configuration.value = configuration.default_value
|
|
configuration.save()
|
|
|
|
# Log reset
|
|
AuditLogger.log_event(
|
|
tenant=tenant,
|
|
event_type='UPDATE',
|
|
event_category='SYSTEM_ADMINISTRATION',
|
|
action='Reset Configuration',
|
|
description=f'Reset configuration {configuration.key} from "{old_value}" to "{configuration.value}"',
|
|
user=request.user,
|
|
content_object=configuration,
|
|
request=request
|
|
)
|
|
|
|
messages.success(request, f'Configuration "{configuration.key}" reset to default value.')
|
|
return redirect('core:system_configuration_detail', pk=pk)
|
|
|
|
|
|
@login_required
|
|
def tenant_stats(request):
|
|
"""
|
|
HTMX view for tenant statistics.
|
|
"""
|
|
|
|
stats = {
|
|
'total_tenants': Tenant.objects.count(),
|
|
'active_tenants': Tenant.objects.filter(is_active=True).count(),
|
|
'inactive_tenants': Tenant.objects.filter(is_active=False).count(),
|
|
'tenants_by_type': Tenant.objects.values('tenant_type').annotate(count=Count('tenant_id')),
|
|
}
|
|
|
|
return render(request, 'core/partials/tenant_stats.html', {'stats': stats})
|
|
|
|
|
|
@login_required
|
|
def configuration_search(request):
|
|
"""
|
|
HTMX view for configuration search.
|
|
"""
|
|
query = request.GET.get('q', '')
|
|
configurations = []
|
|
|
|
if query:
|
|
configurations = SystemConfiguration.objects.filter(
|
|
tenant=request.user.tenant,
|
|
key__icontains=query
|
|
)[:10]
|
|
|
|
return render(request, 'core/partials/configuration_search.html', {
|
|
'configurations': configurations,
|
|
'query': query
|
|
})
|
|
|
|
|
|
@login_required
|
|
def audit_log_list_htmx(request):
|
|
"""
|
|
HTMX view for audit log list.
|
|
"""
|
|
tenant = request.user.tenant
|
|
logs = AuditLog.objects.filter(
|
|
tenant=tenant
|
|
).order_by('-timestamp')[:20]
|
|
|
|
return render(request, 'core/partials/audit_log_list.html', {
|
|
'logs': logs
|
|
})
|
|
|
|
|
|
@login_required
|
|
def activate_tenant(request, pk):
|
|
"""
|
|
Activate a tenant.
|
|
"""
|
|
tenant = get_object_or_404(Tenant, pk=pk)
|
|
tenant.is_active = True
|
|
tenant.save()
|
|
|
|
messages.success(request, f'Tenant "{tenant.name}" has been activated.')
|
|
return redirect('core:tenant_detail', pk=pk)
|
|
|
|
|
|
@login_required
|
|
def deactivate_tenant(request, pk):
|
|
"""
|
|
Deactivate a tenant.
|
|
"""
|
|
tenant = get_object_or_404(Tenant, pk=pk)
|
|
tenant.is_active = False
|
|
tenant.save()
|
|
|
|
messages.success(request, f'Tenant "{tenant.name}" has been deactivated.')
|
|
return redirect('core:tenant_detail', pk=pk)
|
|
|
|
|
|
@login_required
|
|
def reset_system_configuration(request):
|
|
"""
|
|
Reset system configuration to defaults.
|
|
"""
|
|
tenant = request.user.tenant
|
|
if request.method == 'POST':
|
|
# Reset configurations for the tenant
|
|
SystemConfiguration.objects.filter(
|
|
tenant=tenant
|
|
).delete()
|
|
|
|
messages.success(request, 'System configuration has been reset to defaults.')
|
|
return redirect('core:system_configuration_list')
|
|
|
|
return render(request, 'core/configurations/reset_configuration_confirm.html')
|
|
|
|
|
|
@login_required
|
|
def export_audit_log(request):
|
|
"""
|
|
Export audit log to CSV.
|
|
"""
|
|
tenant = request.user.tenant
|
|
response = HttpResponse(content_type='text/csv')
|
|
response['Content-Disposition'] = 'attachment; filename="audit_log.csv"'
|
|
|
|
writer = csv.writer(response)
|
|
writer.writerow(['Timestamp', 'User', 'Action', 'Object Type', 'Object ID', 'Changes'])
|
|
|
|
logs = AuditLog.objects.filter(
|
|
tenant=tenant
|
|
).order_by('-timestamp')
|
|
|
|
for log in logs:
|
|
writer.writerow([
|
|
log.timestamp,
|
|
log.user.username if log.user else 'System',
|
|
log.action,
|
|
log.object_type,
|
|
log.object_id,
|
|
log.changes
|
|
])
|
|
|
|
return response
|
|
|
|
|
|
class CoreSearchView(LoginRequiredMixin, ListView):
|
|
"""
|
|
Generic search view for core models.
|
|
"""
|
|
template_name = 'core/search_results.html'
|
|
context_object_name = 'results'
|
|
paginate_by = 20
|
|
|
|
def get_queryset(self):
|
|
query = self.request.GET.get('q', '')
|
|
if not query:
|
|
return []
|
|
|
|
# Search across multiple models
|
|
results = []
|
|
|
|
# Search tenants
|
|
tenants = Tenant.objects.filter(name__icontains=query)[:5]
|
|
for tenant in tenants:
|
|
results.append({
|
|
'type': 'Tenant',
|
|
'object': tenant,
|
|
'url': reverse('core:tenant_detail', args=[tenant.tenant_id])
|
|
})
|
|
|
|
# Search departments
|
|
departments = Department.objects.filter(
|
|
tenant=self.request.user.tenant,
|
|
name__icontains=query
|
|
)[:5]
|
|
for dept in departments:
|
|
results.append({
|
|
'type': 'Department',
|
|
'object': dept,
|
|
'url': reverse('core:department_detail', args=[dept.department_id])
|
|
})
|
|
|
|
return results
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
context['query'] = self.request.GET.get('q', '')
|
|
return context
|
|
|
|
|
|
@login_required
|
|
def tenant_search(request):
|
|
"""
|
|
AJAX search for tenants.
|
|
"""
|
|
query = request.GET.get('q', '')
|
|
tenants = []
|
|
|
|
if query:
|
|
tenants = Tenant.objects.filter(
|
|
name__icontains=query
|
|
).values('tenant_id', 'name', 'tenant_type')[:10]
|
|
|
|
return JsonResponse({'tenants': list(tenants)})
|
|
|
|
|
|
@login_required
|
|
def bulk_activate_tenants(request):
|
|
"""
|
|
Bulk activate tenants.
|
|
"""
|
|
if request.method == 'POST':
|
|
tenant_ids = request.POST.getlist('tenant_ids')
|
|
count = Tenant.objects.filter(
|
|
tenant_id__in=tenant_ids
|
|
).update(is_active=True)
|
|
|
|
messages.success(request, f'{count} tenants have been activated.')
|
|
|
|
return redirect('core:tenant_list')
|
|
|
|
|
|
@login_required
|
|
def bulk_deactivate_tenants(request):
|
|
"""
|
|
Bulk deactivate tenants.
|
|
"""
|
|
if request.method == 'POST':
|
|
tenant_ids = request.POST.getlist('tenant_ids')
|
|
count = Tenant.objects.filter(
|
|
tenant_id__in=tenant_ids
|
|
).update(is_active=False)
|
|
|
|
messages.success(request, f'{count} tenants have been deactivated.')
|
|
|
|
return redirect('core:tenant_list')
|
|
|
|
|
|
@login_required
|
|
def bulk_export_audit_logs(request):
|
|
"""
|
|
Bulk export audit logs.
|
|
"""
|
|
tenant = request.user.tenant
|
|
|
|
if request.method == 'POST':
|
|
log_ids = request.POST.getlist('log_ids')
|
|
|
|
response = HttpResponse(content_type='text/csv')
|
|
response['Content-Disposition'] = 'attachment; filename="selected_audit_logs.csv"'
|
|
|
|
writer = csv.writer(response)
|
|
writer.writerow(['Timestamp', 'User', 'Action', 'Object Type', 'Object ID', 'Changes'])
|
|
|
|
logs = AuditLog.objects.filter(
|
|
tenant=tenant,
|
|
log_id__in=log_ids
|
|
).order_by('-timestamp')
|
|
|
|
for log in logs:
|
|
writer.writerow([
|
|
log.timestamp,
|
|
log.user.username if log.user else 'System',
|
|
log.action,
|
|
log.object_type,
|
|
log.object_id,
|
|
log.changes
|
|
])
|
|
|
|
return response
|
|
|
|
return redirect('core:audit_log_list')
|
|
|
|
|
|
@login_required
|
|
def validate_tenant_data(request):
|
|
"""
|
|
AJAX validation for tenant data.
|
|
"""
|
|
name = request.GET.get('name', '')
|
|
errors = []
|
|
|
|
if name:
|
|
if Tenant.objects.filter(name=name).exists():
|
|
errors.append('Tenant name already exists.')
|
|
if len(name) < 3:
|
|
errors.append('Tenant name must be at least 3 characters.')
|
|
|
|
return JsonResponse({'valid': len(errors) == 0, 'errors': errors})
|
|
|
|
|
|
@login_required
|
|
def get_system_status(request):
|
|
"""
|
|
Get system status information.
|
|
"""
|
|
import psutil
|
|
from django.db import connection
|
|
|
|
# Database status
|
|
with connection.cursor() as cursor:
|
|
cursor.execute("SELECT 1")
|
|
db_status = "healthy"
|
|
|
|
# System metrics
|
|
status = {
|
|
'database': db_status,
|
|
'cpu_usage': psutil.cpu_percent(),
|
|
'memory_usage': psutil.virtual_memory().percent,
|
|
'disk_usage': psutil.disk_usage('/').percent,
|
|
'active_users': User.objects.filter(is_active=True).count(),
|
|
'total_tenants': Tenant.objects.count(),
|
|
}
|
|
|
|
return JsonResponse(status)
|
|
|
|
|
|
@login_required
|
|
def backup_configuration(request):
|
|
"""
|
|
Backup system configuration.
|
|
"""
|
|
tenant = request.user.tenant
|
|
|
|
configurations = SystemConfiguration.objects.filter(
|
|
tenant=tenant
|
|
).values('key', 'value', 'description')
|
|
|
|
backup_data = {
|
|
'tenant': str(tenant.tenant_id),
|
|
'timestamp': timezone.now().isoformat(),
|
|
'configurations': list(configurations)
|
|
}
|
|
|
|
response = HttpResponse(
|
|
json.dumps(backup_data, indent=2),
|
|
content_type='application/json'
|
|
)
|
|
response['Content-Disposition'] = 'attachment; filename="configuration_backup.json"'
|
|
|
|
return response
|
|
|
|
|
|
@login_required
|
|
def restore_configuration(request):
|
|
"""
|
|
Restore system configuration from backup.
|
|
"""
|
|
tenant = request.user.tenant
|
|
|
|
if request.method == 'POST':
|
|
backup_file = request.FILES.get('backup_file')
|
|
|
|
if backup_file:
|
|
try:
|
|
backup_data = json.loads(backup_file.read().decode('utf-8'))
|
|
|
|
# Clear existing configurations
|
|
SystemConfiguration.objects.filter(
|
|
tenant=tenant
|
|
).delete()
|
|
|
|
# Restore configurations
|
|
for config in backup_data.get('configurations', []):
|
|
SystemConfiguration.objects.create(
|
|
tenant=tenant,
|
|
key=config['key'],
|
|
value=config['value'],
|
|
description=config.get('description', '')
|
|
)
|
|
|
|
messages.success(request, 'Configuration has been restored successfully.')
|
|
return redirect('core:system_configuration_list')
|
|
|
|
except (json.JSONDecodeError, KeyError) as e:
|
|
messages.error(request, f'Invalid backup file: {e}')
|
|
else:
|
|
messages.error(request, 'Please select a backup file.')
|
|
|
|
return render(request, 'core/restore_configuration.html')
|
|
|
|
|
|
@login_required
|
|
def notification_search(request):
|
|
"""API endpoint for searching notifications."""
|
|
user = request.user
|
|
tenant = getattr(user, 'tenant', None)
|
|
|
|
# Get search parameters
|
|
search_term = request.GET.get('term', '')
|
|
notification_type = request.GET.get('notification_type', '')
|
|
is_active = request.GET.get('is_active', '')
|
|
|
|
# Base query
|
|
if user.is_superuser:
|
|
query = SystemNotification.objects.all()
|
|
elif tenant:
|
|
query = SystemNotification.objects.filter(
|
|
Q(tenant=tenant) | Q(tenant__isnull=True)
|
|
)
|
|
else:
|
|
query = SystemNotification.objects.filter(tenant__isnull=True)
|
|
|
|
# Apply filters
|
|
if search_term:
|
|
query = query.filter(
|
|
Q(title__icontains=search_term) |
|
|
Q(message__icontains=search_term)
|
|
)
|
|
|
|
if notification_type:
|
|
query = query.filter(notification_type=notification_type)
|
|
|
|
if is_active:
|
|
is_active_bool = is_active.lower() == 'true'
|
|
query = query.filter(is_active=is_active_bool)
|
|
|
|
# Only include currently visible notifications
|
|
if request.GET.get('visible_only', '') == 'true':
|
|
now = timezone.now()
|
|
query = query.filter(
|
|
is_active=True,
|
|
start_date__lte=now,
|
|
)
|
|
|
|
# Get results
|
|
results = query.order_by('-start_date')[:20]
|
|
|
|
# Format results
|
|
formatted_results = []
|
|
for notification in results:
|
|
# Check if this notification should be visible to the user
|
|
if request.GET.get('check_visibility', '') == 'true':
|
|
if not notification.is_visible_to_user(user):
|
|
continue
|
|
|
|
formatted_results.append({
|
|
'id': str(notification.notification_id),
|
|
'title': notification.title,
|
|
'message': notification.message[:100] + '...' if len(notification.message) > 100 else notification.message,
|
|
'type': notification.notification_type,
|
|
'type_display': notification.get_notification_type_display(),
|
|
'is_active': notification.is_active,
|
|
'is_dismissible': notification.is_dismissible,
|
|
'start_date': notification.start_date.isoformat(),
|
|
'end_date': notification.end_date.isoformat() if notification.end_date else None,
|
|
'url': reverse('core:system_notification_detail', args=[notification.notification_id])
|
|
})
|
|
|
|
return JsonResponse({
|
|
'status': 'success',
|
|
'results': formatted_results,
|
|
'count': len(formatted_results)
|
|
})
|
|
|
|
|
|
|
|
# Department Views
|
|
|
|
# class DepartmentListView(LoginRequiredMixin, ListView):
|
|
# """
|
|
# List departments.
|
|
# """
|
|
# model = Department
|
|
# template_name = 'core/department_list.html'
|
|
# context_object_name = 'departments'
|
|
# paginate_by = 20
|
|
#
|
|
# def get_queryset(self):
|
|
# tenant = self.request.user.tenant
|
|
# if not tenant:
|
|
# return Department.objects.none()
|
|
#
|
|
# queryset = Department.objects.filter(tenant=tenant).order_by('name')
|
|
#
|
|
# # Apply search filter
|
|
# search = self.request.GET.get('search')
|
|
# if search:
|
|
# queryset = queryset.filter(
|
|
# Q(name__icontains=search) |
|
|
# Q(description__icontains=search) |
|
|
# Q(location__icontains=search)
|
|
# )
|
|
#
|
|
# # Apply status filter
|
|
# status = self.request.GET.get('status')
|
|
# if status:
|
|
# queryset = queryset.filter(is_active=(status == 'active'))
|
|
#
|
|
# return queryset
|
|
#
|
|
#
|
|
# class DepartmentDetailView(LoginRequiredMixin, DetailView):
|
|
# """
|
|
# Display department details.
|
|
# """
|
|
# model = Department
|
|
# template_name = 'core/department_detail.html'
|
|
# context_object_name = 'department'
|
|
#
|
|
# def get_queryset(self):
|
|
# tenant = self.request.user.tenant
|
|
# if not tenant:
|
|
# return Department.objects.none()
|
|
# return Department.objects.filter(tenant=tenant)
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# department = self.object
|
|
#
|
|
# # Get department statistics
|
|
# context.update({
|
|
# 'employee_count': department.current_staff_count,
|
|
# 'recent_activity': AuditLogEntry.objects.filter(
|
|
# tenant=department.tenant,
|
|
# object_id=str(department.pk),
|
|
# content_type__model='department'
|
|
# ).order_by('-timestamp')[:10],
|
|
# })
|
|
#
|
|
# return context
|
|
#
|
|
#
|
|
# class DepartmentCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
|
# """
|
|
# Create new department.
|
|
# """
|
|
# model = Department
|
|
# form_class = DepartmentForm
|
|
# template_name = 'core/department_form.html'
|
|
# permission_required = 'core.add_department'
|
|
# success_url = reverse_lazy('core:department_list')
|
|
#
|
|
# def form_valid(self, form):
|
|
# # Set tenant
|
|
# form.instance.tenant = self.request.user.tenant
|
|
# response = super().form_valid(form)
|
|
#
|
|
# # Log department creation
|
|
# AuditLogger.log_event(
|
|
# tenant=form.instance.tenant,
|
|
# event_type='CREATE',
|
|
# event_category='SYSTEM_ADMINISTRATION',
|
|
# action='Create Department',
|
|
# description=f'Created department: {self.object.name}',
|
|
# user=self.request.user,
|
|
# content_object=self.object,
|
|
# request=self.request
|
|
# )
|
|
#
|
|
# messages.success(self.request, f'Department "{self.object.name}" created successfully.')
|
|
# return response
|
|
#
|
|
#
|
|
# class DepartmentUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
|
# """
|
|
# Update department.
|
|
# """
|
|
# model = Department
|
|
# form_class = DepartmentForm
|
|
# template_name = 'core/department_form.html'
|
|
# permission_required = 'core.change_department'
|
|
#
|
|
# def get_queryset(self):
|
|
# tenant = self.request.user.tenant
|
|
# if not tenant:
|
|
# return Department.objects.none()
|
|
# return Department.objects.filter(tenant=tenant)
|
|
#
|
|
# def get_success_url(self):
|
|
# return reverse('core:department_detail', kwargs={'pk': self.object.pk})
|
|
#
|
|
# def form_valid(self, form):
|
|
# response = super().form_valid(form)
|
|
#
|
|
# # Log department update
|
|
# AuditLogger.log_event(
|
|
# tenant=self.object.tenant,
|
|
# event_type='UPDATE',
|
|
# event_category='SYSTEM_ADMINISTRATION',
|
|
# action='Update Department',
|
|
# description=f'Updated department: {self.object.name}',
|
|
# user=self.request.user,
|
|
# content_object=self.object,
|
|
# request=self.request
|
|
# )
|
|
#
|
|
# messages.success(self.request, f'Department "{self.object.name}" updated successfully.')
|
|
# return response
|
|
#
|
|
#
|
|
# class DepartmentDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
|
|
# """
|
|
# Delete department (soft delete to inactive).
|
|
# """
|
|
# model = Department
|
|
# template_name = 'core/department_confirm_delete.html'
|
|
# permission_required = 'core.delete_department'
|
|
# success_url = reverse_lazy('core:department_list')
|
|
#
|
|
# def get_queryset(self):
|
|
# tenant = self.request.user.tenant
|
|
# if not tenant:
|
|
# return Department.objects.none()
|
|
# return Department.objects.filter(tenant=tenant)
|
|
#
|
|
# def delete(self, request, *args, **kwargs):
|
|
# self.object = self.get_object()
|
|
#
|
|
# # Check if department has employees
|
|
# if self.object.get_employee_count() > 0:
|
|
# messages.error(request, 'Cannot delete department with active employees.')
|
|
# return redirect('core:department_detail', pk=self.object.pk)
|
|
#
|
|
# # Soft delete - set to inactive
|
|
# self.object.is_active = False
|
|
# self.object.save()
|
|
#
|
|
# # Log department deletion
|
|
# AuditLogger.log_event(
|
|
# tenant=self.object.tenant,
|
|
# event_type='DELETE',
|
|
# event_category='SYSTEM_ADMINISTRATION',
|
|
# action='Deactivate Department',
|
|
# description=f'Deactivated department: {self.object.name}',
|
|
# user=request.user,
|
|
# content_object=self.object,
|
|
# request=request
|
|
# )
|
|
#
|
|
# messages.success(request, f'Department "{self.object.name}" deactivated successfully.')
|
|
# return redirect(self.success_url)
|
|
#
|
|
# import json
|
|
#
|
|
# from django.contrib.contenttypes.models import ContentType
|
|
# 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, permission_required
|
|
# from django.http import JsonResponse, HttpResponse, HttpResponseRedirect
|
|
# from django.urls import reverse, reverse_lazy
|
|
# from django.db.models import Q, Count, Sum, Avg, F, ExpressionWrapper, DateTimeField
|
|
# from django.utils import timezone
|
|
# from django.utils.translation import gettext_lazy as _
|
|
# from django.contrib import messages
|
|
# from django.core.paginator import Paginator
|
|
# from django.views.decorators.http import require_POST, require_GET
|
|
# from django.views.decorators.csrf import csrf_protect
|
|
# from django.forms import modelform_factory
|
|
# from django.conf import settings
|
|
#
|
|
# from accounts.models import User
|
|
# from .models import (
|
|
# Tenant, Department, AuditLogEntry, SystemConfiguration,
|
|
# SystemNotification, NotificationDismissal, IntegrationLog
|
|
# )
|
|
# from .forms import (
|
|
# TenantForm, DepartmentForm, SystemConfigurationForm, SystemNotificationForm,
|
|
# NotificationDismissForm, IntegrationLogFilterForm, CoreSearchForm
|
|
# )
|
|
#
|
|
#
|
|
# class DashboardView(LoginRequiredMixin, TemplateView):
|
|
# """Main dashboard view for the core app."""
|
|
# template_name = 'core/dashboard.html'
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# user = self.request.user
|
|
# tenant = getattr(user, 'tenant', None)
|
|
#
|
|
# # Default to last 30 days for stats
|
|
# thirty_days_ago = timezone.now() - timezone.timedelta(days=30)
|
|
#
|
|
# # System health summary
|
|
# context['system_health'] = {
|
|
# 'active_tenants': Tenant.objects.filter(is_active=True).count(),
|
|
# 'total_departments': Department.objects.count(),
|
|
# 'system_notifications': SystemNotification.objects.filter(is_active=True,start_date__lte=timezone.now()).count(),
|
|
# }
|
|
#
|
|
# # Recent activities (audit log)
|
|
# if user.is_superuser:
|
|
# # For superusers, show system-wide logs
|
|
# context['recent_activities'] = AuditLogEntry.objects.all().order_by('-timestamp')[:10]
|
|
# elif tenant:
|
|
# # For tenant users, show tenant-specific logs
|
|
# context['recent_activities'] = AuditLogEntry.objects.filter(
|
|
# tenant=tenant
|
|
# ).order_by('-timestamp')[:10]
|
|
# else:
|
|
# context['recent_activities'] = []
|
|
#
|
|
# # Active notifications for user
|
|
# context['notifications'] = []
|
|
# active_notifications = SystemNotification.objects.filter(
|
|
# is_active=True,
|
|
# start_date__lte=timezone.now(),
|
|
# )
|
|
#
|
|
# # Filter to show relevant notifications to this user
|
|
# for notification in active_notifications:
|
|
# if notification.is_visible_to_user(user):
|
|
# context['notifications'].append(notification)
|
|
#
|
|
# # Integration health
|
|
# if user.is_superuser or (user.is_staff and user.has_perm('core.view_integrationlog')):
|
|
# # Calculate success rates for integrations
|
|
# context['integration_health'] = []
|
|
#
|
|
# integrations = IntegrationLog.objects.filter(
|
|
# timestamp__gte=thirty_days_ago
|
|
# ).values('integration_name').distinct()
|
|
#
|
|
# for integration in integrations:
|
|
# integration_name = integration['integration_name']
|
|
# logs = IntegrationLog.objects.filter(
|
|
# integration_name=integration_name,
|
|
# timestamp__gte=thirty_days_ago
|
|
# )
|
|
#
|
|
# total = logs.count()
|
|
# success = logs.filter(status='SUCCESS').count()
|
|
#
|
|
# if total > 0:
|
|
# success_rate = (success / total) * 100
|
|
# else:
|
|
# success_rate = 0
|
|
#
|
|
# context['integration_health'].append({
|
|
# 'name': integration_name,
|
|
# 'success_rate': success_rate,
|
|
# 'total': total,
|
|
# 'success': success,
|
|
# 'error': total - success
|
|
# })
|
|
#
|
|
# return context
|
|
#
|
|
#
|
|
# class TenantListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
|
# """View for listing all tenants."""
|
|
# model = Tenant
|
|
# template_name = 'core/tenant_list.html'
|
|
# context_object_name = 'tenants'
|
|
# paginate_by = 20
|
|
# permission_required = 'core.view_tenant'
|
|
#
|
|
# def get_queryset(self):
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# # Only superusers can see all tenants
|
|
# if not user.is_superuser:
|
|
# # Regular users can only see their own tenant
|
|
# if hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(pk=user.tenant.pk)
|
|
# else:
|
|
# queryset = Tenant.objects.none()
|
|
#
|
|
# # Apply search and filters
|
|
# form = CoreSearchForm(self.request.GET)
|
|
# if form.is_valid():
|
|
# search_term = form.cleaned_data.get('search')
|
|
# org_type = form.cleaned_data.get('organization_type')
|
|
# is_active = form.cleaned_data.get('is_active')
|
|
# created_from = form.cleaned_data.get('created_from')
|
|
# created_to = form.cleaned_data.get('created_to')
|
|
#
|
|
# if search_term:
|
|
# queryset = queryset.filter(
|
|
# Q(name__icontains=search_term) |
|
|
# Q(code__icontains=search_term) |
|
|
# Q(contact_email__icontains=search_term) |
|
|
# Q(description__icontains=search_term)
|
|
# )
|
|
#
|
|
# if org_type:
|
|
# queryset = queryset.filter(organization_type=org_type)
|
|
#
|
|
# if is_active:
|
|
# is_active_bool = is_active == 'true'
|
|
# queryset = queryset.filter(is_active=is_active_bool)
|
|
#
|
|
# if created_from:
|
|
# queryset = queryset.filter(created_at__date__gte=created_from)
|
|
#
|
|
# if created_to:
|
|
# queryset = queryset.filter(created_at__date__lte=created_to)
|
|
#
|
|
# return queryset.select_related('created_by')
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# context['search_form'] = CoreSearchForm(self.request.GET)
|
|
# return context
|
|
#
|
|
#
|
|
# class TenantDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
|
# """View for displaying tenant details."""
|
|
# model = Tenant
|
|
# template_name = 'core/tenant_detail.html'
|
|
# context_object_name = 'tenant'
|
|
# permission_required = 'core.view_tenant'
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# tenant = self.get_object()
|
|
#
|
|
# # Get departments for this tenant
|
|
# context['departments'] = Department.objects.filter(
|
|
# tenant=tenant
|
|
# ).select_related('department_head', 'parent_department')
|
|
#
|
|
# # Count users by role
|
|
# if hasattr(tenant, 'users'):
|
|
# user_roles = tenant.users.values('role').annotate(count=Count('id'))
|
|
# context['user_roles'] = user_roles
|
|
#
|
|
# # Get tenant-specific configurations
|
|
# context['configurations'] = SystemConfiguration.objects.filter(
|
|
# tenant=tenant
|
|
# ).order_by('category', 'key')
|
|
#
|
|
# # Get recent audit logs
|
|
# context['audit_logs'] = AuditLogEntry.objects.filter(
|
|
# tenant=tenant
|
|
# ).order_by('-timestamp')[:10]
|
|
#
|
|
# # Check subscription status
|
|
# context['subscription_valid'] = tenant.is_subscription_valid()
|
|
#
|
|
# # Tenant statistics
|
|
# context['active_users_count'] = tenant.get_active_users_count()
|
|
#
|
|
# # Departments by type
|
|
# dept_by_type = Department.objects.filter(
|
|
# tenant=tenant
|
|
# ).values('department_type').annotate(count=Count('department_id'))
|
|
# context['departments_by_type'] = dept_by_type
|
|
#
|
|
# return context
|
|
#
|
|
#
|
|
# class TenantCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
|
# """View for creating a new tenant."""
|
|
# model = Tenant
|
|
# form_class = TenantForm
|
|
# template_name = 'core/tenant_form.html'
|
|
# permission_required = 'core.add_tenant'
|
|
# success_url = reverse_lazy('core:tenant_list')
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# context['title'] = _('Create New Tenant')
|
|
# return context
|
|
#
|
|
# def form_valid(self, form):
|
|
# """Set the created_by field to the current user."""
|
|
# form.instance.created_by = self.request.user
|
|
#
|
|
# response = super().form_valid(form)
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=self.request.user,
|
|
# action_type='CREATE',
|
|
# content_object=self.object,
|
|
# request=self.request
|
|
# )
|
|
#
|
|
# messages.success(
|
|
# self.request,
|
|
# _('Tenant "{}" was created successfully.').format(self.object.name)
|
|
# )
|
|
#
|
|
# return response
|
|
#
|
|
# def form_invalid(self, form):
|
|
# """Handle form validation errors."""
|
|
# messages.error(
|
|
# self.request,
|
|
# _('There was an error creating the tenant. Please check the form.')
|
|
# )
|
|
# return super().form_invalid(form)
|
|
#
|
|
#
|
|
# class TenantUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
|
# """View for updating a tenant."""
|
|
# model = Tenant
|
|
# form_class = TenantForm
|
|
# template_name = 'core/tenant_form.html'
|
|
# permission_required = 'core.change_tenant'
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# context['title'] = _('Update Tenant')
|
|
# return context
|
|
#
|
|
# def get_success_url(self):
|
|
# """Return to the tenant detail page after update."""
|
|
# return reverse('core:tenant_detail', kwargs={'pk': self.object.pk})
|
|
#
|
|
# def form_valid(self, form):
|
|
# """Log the update action."""
|
|
# # Capture changes
|
|
# if self.object:
|
|
# changes = {}
|
|
# for field in form.changed_data:
|
|
# if field not in ['logo']: # Skip binary fields
|
|
# old_value = getattr(self.object, field)
|
|
# new_value = form.cleaned_data[field]
|
|
# changes[field] = {
|
|
# 'old': str(old_value),
|
|
# 'new': str(new_value)
|
|
# }
|
|
#
|
|
# response = super().form_valid(form)
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=self.request.user,
|
|
# action_type='UPDATE',
|
|
# content_object=self.object,
|
|
# changes=changes,
|
|
# request=self.request
|
|
# )
|
|
#
|
|
# messages.success(
|
|
# self.request,
|
|
# _('Tenant "{}" was updated successfully.').format(self.object.name)
|
|
# )
|
|
#
|
|
# return response
|
|
#
|
|
# def form_invalid(self, form):
|
|
# """Handle form validation errors."""
|
|
# messages.error(
|
|
# self.request,
|
|
# _('There was an error updating the tenant. Please check the form.')
|
|
# )
|
|
# return super().form_invalid(form)
|
|
#
|
|
#
|
|
# class TenantDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
|
|
# """View for deleting a tenant."""
|
|
# model = Tenant
|
|
# template_name = 'core/tenant_confirm_delete.html'
|
|
# permission_required = 'core.delete_tenant'
|
|
# success_url = reverse_lazy('core:tenant_list')
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
#
|
|
# # Count related objects to warn user
|
|
# tenant = self.get_object()
|
|
# context['departments_count'] = tenant.departments.count()
|
|
#
|
|
# # Count users if there's a relationship
|
|
# if hasattr(tenant, 'users'):
|
|
# context['users_count'] = tenant.users.count()
|
|
#
|
|
# return context
|
|
#
|
|
# def delete(self, request, *args, **kwargs):
|
|
# """Override delete to log the action."""
|
|
# self.object = self.get_object()
|
|
# name = self.object.name
|
|
#
|
|
# # Log the action before deletion
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='DELETE',
|
|
# content_object=self.object,
|
|
# request=request
|
|
# )
|
|
#
|
|
# # Proceed with deletion
|
|
# success_url = self.get_success_url()
|
|
# self.object.delete()
|
|
#
|
|
# messages.success(
|
|
# request,
|
|
# _('Tenant "{}" was deleted successfully.').format(name)
|
|
# )
|
|
#
|
|
# return HttpResponseRedirect(success_url)
|
|
#
|
|
#
|
|
# class DepartmentListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
|
# """View for listing departments."""
|
|
# model = Department
|
|
# template_name = 'core/department_list.html'
|
|
# context_object_name = 'departments'
|
|
# paginate_by = 20
|
|
# permission_required = 'core.view_department'
|
|
#
|
|
# def get_queryset(self):
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# # Filter by tenant
|
|
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(tenant=user.tenant)
|
|
#
|
|
# # Apply search and filters
|
|
# form = CoreSearchForm(self.request.GET)
|
|
# if form.is_valid():
|
|
# search_term = form.cleaned_data.get('search')
|
|
# dept_type = form.cleaned_data.get('department_type')
|
|
# is_active = form.cleaned_data.get('is_active')
|
|
# created_from = form.cleaned_data.get('created_from')
|
|
# created_to = form.cleaned_data.get('created_to')
|
|
#
|
|
# if search_term:
|
|
# queryset = queryset.filter(
|
|
# Q(name__icontains=search_term) |
|
|
# Q(code__icontains=search_term) |
|
|
# Q(description__icontains=search_term)
|
|
# )
|
|
#
|
|
# if dept_type:
|
|
# queryset = queryset.filter(department_type=dept_type)
|
|
#
|
|
# if is_active:
|
|
# is_active_bool = is_active == 'true'
|
|
# queryset = queryset.filter(is_active=is_active_bool)
|
|
#
|
|
# if created_from:
|
|
# queryset = queryset.filter(created_at__date__gte=created_from)
|
|
#
|
|
# if created_to:
|
|
# queryset = queryset.filter(created_at__date__lte=created_to)
|
|
#
|
|
# return queryset.select_related('tenant', 'department_head', 'parent_department')
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# context['search_form'] = CoreSearchForm(self.request.GET)
|
|
#
|
|
# # Get tenant list for superusers
|
|
# if self.request.user.is_superuser:
|
|
# context['tenants'] = Tenant.objects.filter(is_active=True)
|
|
#
|
|
# # Department types for quick filtering
|
|
# context['department_types'] = dict(Department.DEPARTMENT_TYPE_CHOICES)
|
|
#
|
|
# return context
|
|
#
|
|
#
|
|
# class DepartmentDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
|
# """View for displaying department details."""
|
|
# model = Department
|
|
# template_name = 'core/department_detail.html'
|
|
# context_object_name = 'department'
|
|
# permission_required = 'core.view_department'
|
|
#
|
|
# def get_queryset(self):
|
|
# """Filter by user's tenant if not superuser."""
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(tenant=user.tenant)
|
|
#
|
|
# return queryset.select_related(
|
|
# 'tenant', 'department_head', 'parent_department', 'created_by'
|
|
# )
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# department = self.get_object()
|
|
#
|
|
# # Get sub-departments
|
|
# context['sub_departments'] = department.sub_departments.all()
|
|
#
|
|
# # Get staff members
|
|
# if hasattr(department, 'staff'):
|
|
# context['staff_members'] = department.staff.all()
|
|
#
|
|
# # Get department hierarchy
|
|
# hierarchy = []
|
|
# current = department
|
|
# while current.parent_department:
|
|
# hierarchy.insert(0, current.parent_department)
|
|
# current = current.parent_department
|
|
# context['department_hierarchy'] = hierarchy
|
|
#
|
|
# # Format operating hours for display
|
|
# if department.operating_hours:
|
|
# try:
|
|
# if isinstance(department.operating_hours, str):
|
|
# hours = json.loads(department.operating_hours)
|
|
# else:
|
|
# hours = department.operating_hours
|
|
# context['operating_hours_formatted'] = hours
|
|
# except json.JSONDecodeError:
|
|
# context['operating_hours_formatted'] = None
|
|
#
|
|
# return context
|
|
#
|
|
#
|
|
# class DepartmentCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
|
# """View for creating a new department."""
|
|
# model = Department
|
|
# form_class = DepartmentForm
|
|
# template_name = 'core/department_form.html'
|
|
# permission_required = 'core.add_department'
|
|
#
|
|
# def get_form_kwargs(self):
|
|
# """Pass the current user to the form."""
|
|
# kwargs = super().get_form_kwargs()
|
|
# kwargs['user'] = self.request.user
|
|
# return kwargs
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# context['title'] = _('Create New Department')
|
|
# return context
|
|
#
|
|
# def form_valid(self, form):
|
|
# """Set the created_by field to the current user."""
|
|
# form.instance.created_by = self.request.user
|
|
#
|
|
# # Set tenant automatically for non-superusers
|
|
# if not self.request.user.is_superuser and hasattr(self.request.user, 'tenant'):
|
|
# form.instance.tenant = self.request.user.tenant
|
|
#
|
|
# response = super().form_valid(form)
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=self.request.user,
|
|
# action_type='CREATE',
|
|
# content_object=self.object,
|
|
# request=self.request
|
|
# )
|
|
#
|
|
# messages.success(
|
|
# self.request,
|
|
# _('Department "{}" was created successfully.').format(self.object.name)
|
|
# )
|
|
#
|
|
# return response
|
|
#
|
|
# def get_success_url(self):
|
|
# """Return to the department detail page after creation."""
|
|
# return reverse('core:department_detail', kwargs={'pk': self.object.pk})
|
|
#
|
|
# def form_invalid(self, form):
|
|
# """Handle form validation errors."""
|
|
# messages.error(
|
|
# self.request,
|
|
# _('There was an error creating the department. Please check the form.')
|
|
# )
|
|
# return super().form_invalid(form)
|
|
#
|
|
#
|
|
# class DepartmentUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
|
# """View for updating a department."""
|
|
# model = Department
|
|
# form_class = DepartmentForm
|
|
# template_name = 'core/department_form.html'
|
|
# permission_required = 'core.change_department'
|
|
#
|
|
# def get_queryset(self):
|
|
# """Filter by user's tenant if not superuser."""
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(tenant=user.tenant)
|
|
#
|
|
# return queryset
|
|
#
|
|
# def get_form_kwargs(self):
|
|
# """Pass the current user to the form."""
|
|
# kwargs = super().get_form_kwargs()
|
|
# kwargs['user'] = self.request.user
|
|
# return kwargs
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# context['title'] = _('Update Department')
|
|
# return context
|
|
#
|
|
# def form_valid(self, form):
|
|
# """Log the update action."""
|
|
# # Capture changes
|
|
# if self.object:
|
|
# changes = {}
|
|
# for field in form.changed_data:
|
|
# old_value = getattr(self.object, field)
|
|
# new_value = form.cleaned_data[field]
|
|
# changes[field] = {
|
|
# 'old': str(old_value),
|
|
# 'new': str(new_value)
|
|
# }
|
|
#
|
|
# response = super().form_valid(form)
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=self.request.user,
|
|
# action_type='UPDATE',
|
|
# content_object=self.object,
|
|
# changes=changes,
|
|
# request=self.request
|
|
# )
|
|
#
|
|
# messages.success(
|
|
# self.request,
|
|
# _('Department "{}" was updated successfully.').format(self.object.name)
|
|
# )
|
|
#
|
|
# return response
|
|
#
|
|
# def get_success_url(self):
|
|
# """Return to the department detail page after update."""
|
|
# return reverse('core:department_detail', kwargs={'pk': self.object.pk})
|
|
#
|
|
# def form_invalid(self, form):
|
|
# """Handle form validation errors."""
|
|
# messages.error(
|
|
# self.request,
|
|
# _('There was an error updating the department. Please check the form.')
|
|
# )
|
|
# return super().form_invalid(form)
|
|
#
|
|
#
|
|
# class DepartmentDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
|
|
# """View for deleting a department."""
|
|
# model = Department
|
|
# template_name = 'core/department_confirm_delete.html'
|
|
# permission_required = 'core.delete_department'
|
|
#
|
|
# def get_queryset(self):
|
|
# """Filter by user's tenant if not superuser."""
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(tenant=user.tenant)
|
|
#
|
|
# return queryset
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
#
|
|
# # Count related objects to warn user
|
|
# department = self.get_object()
|
|
# context['sub_departments_count'] = department.sub_departments.count()
|
|
#
|
|
# # Check for staff members if there's a relationship
|
|
# if hasattr(department, 'staff'):
|
|
# context['staff_count'] = department.staff.count()
|
|
#
|
|
# return context
|
|
#
|
|
# def delete(self, request, *args, **kwargs):
|
|
# """Override delete to log the action."""
|
|
# self.object = self.get_object()
|
|
# name = self.object.name
|
|
# tenant = self.object.tenant
|
|
#
|
|
# # Log the action before deletion
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='DELETE',
|
|
# content_object=self.object,
|
|
# request=request
|
|
# )
|
|
#
|
|
# # Proceed with deletion
|
|
# self.object.delete()
|
|
#
|
|
# messages.success(
|
|
# request,
|
|
# _('Department "{}" was deleted successfully.').format(name)
|
|
# )
|
|
#
|
|
# # Return to department list
|
|
# return HttpResponseRedirect(reverse('core:department_list'))
|
|
#
|
|
#
|
|
# class AuditLogListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
|
# """View for listing audit logs."""
|
|
# model = AuditLogEntry
|
|
# template_name = 'core/audit_log_list.html'
|
|
# context_object_name = 'audit_logs'
|
|
# paginate_by = 50
|
|
# permission_required = 'core.view_auditlogentry'
|
|
#
|
|
# def get_queryset(self):
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# # Filter by tenant for non-superusers
|
|
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(tenant=user.tenant)
|
|
#
|
|
# # Apply filters
|
|
# filters = {}
|
|
#
|
|
# action_type = self.request.GET.get('action_type')
|
|
# if action_type:
|
|
# filters['action_type'] = action_type
|
|
#
|
|
# user_id = self.request.GET.get('user')
|
|
# if user_id:
|
|
# filters['user_id'] = user_id
|
|
#
|
|
# content_type_id = self.request.GET.get('content_type')
|
|
# if content_type_id:
|
|
# filters['content_type_id'] = content_type_id
|
|
#
|
|
# date_from = self.request.GET.get('date_from')
|
|
# if date_from:
|
|
# filters['timestamp__date__gte'] = date_from
|
|
#
|
|
# date_to = self.request.GET.get('date_to')
|
|
# if date_to:
|
|
# filters['timestamp__date__lte'] = date_to
|
|
#
|
|
# # Apply search term
|
|
# search_term = self.request.GET.get('search')
|
|
# if search_term:
|
|
# queryset = queryset.filter(
|
|
# Q(username__icontains=search_term) |
|
|
# Q(object_repr__icontains=search_term) |
|
|
# Q(ip_address__icontains=search_term)
|
|
# )
|
|
#
|
|
# # Apply filters
|
|
# if filters:
|
|
# queryset = queryset.filter(**filters)
|
|
#
|
|
# return queryset.select_related('user', 'content_type').order_by('-timestamp')
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
#
|
|
# # Add filter options
|
|
# context['action_types'] = dict(AuditLogEntry.ACTION_TYPE_CHOICES)
|
|
#
|
|
# # Add content types for filtering
|
|
# context['content_types'] = ContentType.objects.filter(
|
|
# id__in=AuditLogEntry.objects.values_list('content_type_id', flat=True).distinct()
|
|
# )
|
|
#
|
|
# # Add users for filtering
|
|
# user_ids = AuditLogEntry.objects.values_list('user_id', flat=True).distinct()
|
|
# context['users'] = User.objects.filter(id__in=user_ids)
|
|
#
|
|
# # Current filters
|
|
# context['current_filters'] = {
|
|
# 'action_type': self.request.GET.get('action_type', ''),
|
|
# 'user': self.request.GET.get('user', ''),
|
|
# 'content_type': self.request.GET.get('content_type', ''),
|
|
# 'date_from': self.request.GET.get('date_from', ''),
|
|
# 'date_to': self.request.GET.get('date_to', ''),
|
|
# 'search': self.request.GET.get('search', '')
|
|
# }
|
|
#
|
|
# return context
|
|
#
|
|
#
|
|
# class AuditLogDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
|
# """View for displaying audit log details."""
|
|
# model = AuditLogEntry
|
|
# template_name = 'core/audit_log_detail.html'
|
|
# context_object_name = 'audit_log'
|
|
# permission_required = 'core.view_auditlogentry'
|
|
#
|
|
# def get_queryset(self):
|
|
# """Filter by user's tenant if not superuser."""
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# if not user.is_superuser and hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(tenant=user.tenant)
|
|
#
|
|
# return queryset.select_related('user', 'content_type')
|
|
#
|
|
#
|
|
# class SystemConfigurationListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
|
# """View for listing system configurations."""
|
|
# model = SystemConfiguration
|
|
# template_name = 'core/system_configuration_list.html'
|
|
# context_object_name = 'configurations'
|
|
# paginate_by = 50
|
|
# permission_required = 'core.view_systemconfiguration'
|
|
#
|
|
# def get_queryset(self):
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# # Filter by tenant for non-superusers
|
|
# if not user.is_superuser:
|
|
# if hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(Q(tenant=user.tenant) | Q(tenant__isnull=True))
|
|
# else:
|
|
# queryset = queryset.filter(tenant__isnull=True)
|
|
#
|
|
# # Apply filters
|
|
# category = self.request.GET.get('category')
|
|
# if category:
|
|
# queryset = queryset.filter(category=category)
|
|
#
|
|
# tenant_id = self.request.GET.get('tenant')
|
|
# if tenant_id:
|
|
# if tenant_id == 'system':
|
|
# queryset = queryset.filter(tenant__isnull=True)
|
|
# else:
|
|
# queryset = queryset.filter(tenant_id=tenant_id)
|
|
#
|
|
# # Apply search
|
|
# search_term = self.request.GET.get('search')
|
|
# if search_term:
|
|
# queryset = queryset.filter(
|
|
# Q(key__icontains=search_term) |
|
|
# Q(description__icontains=search_term)
|
|
# )
|
|
#
|
|
# return queryset.select_related('tenant').order_by('category', 'key')
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
#
|
|
# # Add filter options
|
|
# context['categories'] = dict(SystemConfiguration.CATEGORY_CHOICES)
|
|
#
|
|
# # Add tenants for filtering if superuser
|
|
# if self.request.user.is_superuser:
|
|
# context['tenants'] = Tenant.objects.filter(is_active=True)
|
|
#
|
|
# # Group configurations by category
|
|
# configurations_by_category = {}
|
|
#
|
|
# for config in context['configurations']:
|
|
# category = config.get_category_display()
|
|
# if category not in configurations_by_category:
|
|
# configurations_by_category[category] = []
|
|
# configurations_by_category[category].append(config)
|
|
#
|
|
# context['configurations_by_category'] = configurations_by_category
|
|
#
|
|
# # Current filters
|
|
# context['current_filters'] = {
|
|
# 'category': self.request.GET.get('category', ''),
|
|
# 'tenant': self.request.GET.get('tenant', ''),
|
|
# 'search': self.request.GET.get('search', '')
|
|
# }
|
|
#
|
|
# return context
|
|
#
|
|
#
|
|
# class SystemConfigurationDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
|
# """View for displaying system configuration details."""
|
|
# model = SystemConfiguration
|
|
# template_name = 'core/system_configuration_detail.html'
|
|
# context_object_name = 'configuration'
|
|
# permission_required = 'core.view_systemconfiguration'
|
|
#
|
|
# def get_queryset(self):
|
|
# """Filter by user's tenant if not superuser."""
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# if not user.is_superuser:
|
|
# if hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(Q(tenant=user.tenant) | Q(tenant__isnull=True))
|
|
# else:
|
|
# queryset = queryset.filter(tenant__isnull=True)
|
|
#
|
|
# return queryset.select_related('tenant', 'created_by')
|
|
#
|
|
#
|
|
# class SystemConfigurationCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
|
# """View for creating a new system configuration."""
|
|
# model = SystemConfiguration
|
|
# form_class = SystemConfigurationForm
|
|
# template_name = 'core/system_configuration_form.html'
|
|
# permission_required = 'core.add_systemconfiguration'
|
|
#
|
|
# def get_form_kwargs(self):
|
|
# """Pass the current user to the form."""
|
|
# kwargs = super().get_form_kwargs()
|
|
# kwargs['user'] = self.request.user
|
|
# return kwargs
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# context['title'] = _('Create New Configuration')
|
|
# return context
|
|
#
|
|
# def form_valid(self, form):
|
|
# """Set the created_by field to the current user."""
|
|
# form.instance.created_by = self.request.user
|
|
#
|
|
# # Set tenant automatically for non-superusers
|
|
# if not self.request.user.is_superuser and hasattr(self.request.user, 'tenant'):
|
|
# form.instance.tenant = self.request.user.tenant
|
|
#
|
|
# response = super().form_valid(form)
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=self.request.user,
|
|
# action_type='CREATE',
|
|
# content_object=self.object,
|
|
# request=self.request
|
|
# )
|
|
#
|
|
# messages.success(
|
|
# self.request,
|
|
# _('Configuration "{}" was created successfully.').format(self.object.key)
|
|
# )
|
|
#
|
|
# return response
|
|
#
|
|
# def get_success_url(self):
|
|
# """Return to the configuration detail page after creation."""
|
|
# return reverse('core:system_configuration_detail', kwargs={'pk': self.object.pk})
|
|
#
|
|
# def form_invalid(self, form):
|
|
# """Handle form validation errors."""
|
|
# messages.error(
|
|
# self.request,
|
|
# _('There was an error creating the configuration. Please check the form.')
|
|
# )
|
|
# return super().form_invalid(form)
|
|
#
|
|
#
|
|
# class SystemConfigurationUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
|
# """View for updating a system configuration."""
|
|
# model = SystemConfiguration
|
|
# form_class = SystemConfigurationForm
|
|
# template_name = 'core/system_configuration_form.html'
|
|
# permission_required = 'core.change_systemconfiguration'
|
|
#
|
|
# def get_queryset(self):
|
|
# """Filter by user's tenant if not superuser."""
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# if not user.is_superuser:
|
|
# if hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(
|
|
# Q(tenant=user.tenant) |
|
|
# Q(tenant__isnull=True, is_tenant_editable=True)
|
|
# )
|
|
# else:
|
|
# queryset = queryset.none()
|
|
#
|
|
# return queryset
|
|
#
|
|
# def get_form_kwargs(self):
|
|
# """Pass the current user to the form."""
|
|
# kwargs = super().get_form_kwargs()
|
|
# kwargs['user'] = self.request.user
|
|
# return kwargs
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# context['title'] = _('Update Configuration')
|
|
# return context
|
|
#
|
|
# def form_valid(self, form):
|
|
# """Log the update action."""
|
|
# # Capture changes
|
|
# if self.object:
|
|
# changes = {}
|
|
# for field in form.changed_data:
|
|
# old_value = getattr(self.object, field)
|
|
# new_value = form.cleaned_data[field]
|
|
#
|
|
# # Handle encrypted values
|
|
# if field == 'value' and self.object.is_encrypted:
|
|
# old_value = '********'
|
|
# new_value = '********'
|
|
#
|
|
# changes[field] = {
|
|
# 'old': str(old_value),
|
|
# 'new': str(new_value)
|
|
# }
|
|
#
|
|
# response = super().form_valid(form)
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=self.request.user,
|
|
# action_type='UPDATE',
|
|
# content_object=self.object,
|
|
# changes=changes,
|
|
# request=self.request
|
|
# )
|
|
#
|
|
# messages.success(
|
|
# self.request,
|
|
# _('Configuration "{}" was updated successfully.').format(self.object.key)
|
|
# )
|
|
#
|
|
# # Check if restart is required
|
|
# if self.object.requires_restart:
|
|
# messages.warning(
|
|
# self.request,
|
|
# _('This configuration change requires a system restart to take effect.')
|
|
# )
|
|
#
|
|
# return response
|
|
#
|
|
# def get_success_url(self):
|
|
# """Return to the configuration detail page after update."""
|
|
# return reverse('core:system_configuration_detail', kwargs={'pk': self.object.pk})
|
|
#
|
|
# def form_invalid(self, form):
|
|
# """Handle form validation errors."""
|
|
# messages.error(
|
|
# self.request,
|
|
# _('There was an error updating the configuration. Please check the form.')
|
|
# )
|
|
# return super().form_invalid(form)
|
|
#
|
|
#
|
|
# class SystemConfigurationDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
|
|
# """View for deleting a system configuration."""
|
|
# model = SystemConfiguration
|
|
# template_name = 'core/system_configuration_confirm_delete.html'
|
|
# permission_required = 'core.delete_systemconfiguration'
|
|
#
|
|
# def get_queryset(self):
|
|
# """Filter by user's tenant if not superuser."""
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# if not user.is_superuser:
|
|
# if hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(tenant=user.tenant)
|
|
# else:
|
|
# queryset = queryset.none()
|
|
#
|
|
# return queryset
|
|
#
|
|
# def delete(self, request, *args, **kwargs):
|
|
# """Override delete to log the action."""
|
|
# self.object = self.get_object()
|
|
# key = self.object.key
|
|
#
|
|
# # Log the action before deletion
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='DELETE',
|
|
# content_object=self.object,
|
|
# request=request
|
|
# )
|
|
#
|
|
# # Proceed with deletion
|
|
# self.object.delete()
|
|
#
|
|
# messages.success(
|
|
# request,
|
|
# _('Configuration "{}" was deleted successfully.').format(key)
|
|
# )
|
|
#
|
|
# # Return to configuration list
|
|
# return HttpResponseRedirect(reverse('core:system_configuration_list'))
|
|
#
|
|
#
|
|
# class SystemNotificationListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
|
# """View for listing system notifications."""
|
|
# model = SystemNotification
|
|
# template_name = 'core/system_notification_list.html'
|
|
# context_object_name = 'notifications'
|
|
# paginate_by = 20
|
|
# permission_required = 'core.view_systemnotification'
|
|
#
|
|
# def get_queryset(self):
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# # Filter by tenant for non-superusers
|
|
# if not user.is_superuser:
|
|
# if hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(Q(tenant=user.tenant) | Q(tenant__isnull=True))
|
|
# else:
|
|
# queryset = queryset.filter(tenant__isnull=True)
|
|
#
|
|
# # Apply filters
|
|
# notification_type = self.request.GET.get('notification_type')
|
|
# if notification_type:
|
|
# queryset = queryset.filter(notification_type=notification_type)
|
|
#
|
|
# visibility = self.request.GET.get('visibility')
|
|
# if visibility:
|
|
# queryset = queryset.filter(visibility=visibility)
|
|
#
|
|
# is_active = self.request.GET.get('is_active')
|
|
# if is_active is not None:
|
|
# is_active_bool = is_active.lower() == 'true'
|
|
# queryset = queryset.filter(is_active=is_active_bool)
|
|
#
|
|
# # Apply search
|
|
# search_term = self.request.GET.get('search')
|
|
# if search_term:
|
|
# queryset = queryset.filter(
|
|
# Q(title__icontains=search_term) |
|
|
# Q(message__icontains=search_term)
|
|
# )
|
|
#
|
|
# return queryset.select_related('tenant', 'created_by').order_by('-start_date')
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
#
|
|
# # Add filter options
|
|
# context['notification_types'] = dict(SystemNotification.NOTIFICATION_TYPE_CHOICES)
|
|
# context['visibility_options'] = dict(SystemNotification.VISIBILITY_CHOICES)
|
|
#
|
|
# # Current filters
|
|
# context['current_filters'] = {
|
|
# 'notification_type': self.request.GET.get('notification_type', ''),
|
|
# 'visibility': self.request.GET.get('visibility', ''),
|
|
# 'is_active': self.request.GET.get('is_active', ''),
|
|
# 'search': self.request.GET.get('search', '')
|
|
# }
|
|
#
|
|
# return context
|
|
#
|
|
#
|
|
# class SystemNotificationDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
|
# """View for displaying system notification details."""
|
|
# model = SystemNotification
|
|
# template_name = 'core/system_notification_detail.html'
|
|
# context_object_name = 'notification'
|
|
# permission_required = 'core.view_systemnotification'
|
|
#
|
|
# def get_queryset(self):
|
|
# """Filter by user's tenant if not superuser."""
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# if not user.is_superuser:
|
|
# if hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(Q(tenant=user.tenant) | Q(tenant__isnull=True))
|
|
# else:
|
|
# queryset = queryset.filter(tenant__isnull=True)
|
|
#
|
|
# return queryset.select_related('tenant', 'created_by')
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# notification = self.get_object()
|
|
#
|
|
# # Check if user has dismissed this notification
|
|
# if notification.is_dismissible:
|
|
# context['is_dismissed'] = notification.dismissals.filter(
|
|
# pk=self.request.user.pk
|
|
# ).exists()
|
|
#
|
|
# # Get dismissal count
|
|
# context['dismissal_count'] = notification.dismissals.count()
|
|
#
|
|
# # Get user groups that can see this notification
|
|
# if notification.visibility == 'CUSTOM':
|
|
# context['target_groups'] = notification.target_groups.all()
|
|
#
|
|
# return context
|
|
#
|
|
#
|
|
# class SystemNotificationCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
|
# """View for creating a new system notification."""
|
|
# model = SystemNotification
|
|
# form_class = SystemNotificationForm
|
|
# template_name = 'core/system_notification_form.html'
|
|
# permission_required = 'core.add_systemnotification'
|
|
#
|
|
# def get_form_kwargs(self):
|
|
# """Pass the current user to the form."""
|
|
# kwargs = super().get_form_kwargs()
|
|
# kwargs['user'] = self.request.user
|
|
# return kwargs
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# context['title'] = _('Create New Notification')
|
|
# return context
|
|
#
|
|
# def form_valid(self, form):
|
|
# """Set the created_by field to the current user."""
|
|
# form.instance.created_by = self.request.user
|
|
#
|
|
# # Set tenant automatically for non-superusers
|
|
# if not self.request.user.is_superuser and hasattr(self.request.user, 'tenant'):
|
|
# form.instance.tenant = self.request.user.tenant
|
|
#
|
|
# response = super().form_valid(form)
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=self.request.user,
|
|
# action_type='CREATE',
|
|
# content_object=self.object,
|
|
# request=self.request
|
|
# )
|
|
#
|
|
# messages.success(
|
|
# self.request,
|
|
# _('Notification "{}" was created successfully.').format(self.object.title)
|
|
# )
|
|
#
|
|
# return response
|
|
#
|
|
# def get_success_url(self):
|
|
# """Return to the notification detail page after creation."""
|
|
# return reverse('core:system_notification_detail', kwargs={'pk': self.object.pk})
|
|
#
|
|
# def form_invalid(self, form):
|
|
# """Handle form validation errors."""
|
|
# messages.error(
|
|
# self.request,
|
|
# _('There was an error creating the notification. Please check the form.')
|
|
# )
|
|
# return super().form_invalid(form)
|
|
#
|
|
#
|
|
# class SystemNotificationUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
|
# """View for updating a system notification."""
|
|
# model = SystemNotification
|
|
# form_class = SystemNotificationForm
|
|
# template_name = 'core/system_notification_form.html'
|
|
# permission_required = 'core.change_systemnotification'
|
|
#
|
|
# def get_queryset(self):
|
|
# """Filter by user's tenant if not superuser."""
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# if not user.is_superuser:
|
|
# if hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(tenant=user.tenant)
|
|
# else:
|
|
# queryset = queryset.none()
|
|
#
|
|
# return queryset
|
|
#
|
|
# def get_form_kwargs(self):
|
|
# """Pass the current user to the form."""
|
|
# kwargs = super().get_form_kwargs()
|
|
# kwargs['user'] = self.request.user
|
|
# return kwargs
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# context['title'] = _('Update Notification')
|
|
# return context
|
|
#
|
|
# def form_valid(self, form):
|
|
# """Log the update action."""
|
|
# # Capture changes
|
|
# if self.object:
|
|
# changes = {}
|
|
# for field in form.changed_data:
|
|
# if field != 'target_groups': # M2M requires special handling
|
|
# old_value = getattr(self.object, field)
|
|
# new_value = form.cleaned_data[field]
|
|
# changes[field] = {
|
|
# 'old': str(old_value),
|
|
# 'new': str(new_value)
|
|
# }
|
|
#
|
|
# response = super().form_valid(form)
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=self.request.user,
|
|
# action_type='UPDATE',
|
|
# content_object=self.object,
|
|
# changes=changes,
|
|
# request=self.request
|
|
# )
|
|
#
|
|
# messages.success(
|
|
# self.request,
|
|
# _('Notification "{}" was updated successfully.').format(self.object.title)
|
|
# )
|
|
#
|
|
# return response
|
|
#
|
|
# def get_success_url(self):
|
|
# """Return to the notification detail page after update."""
|
|
# return reverse('core:system_notification_detail', kwargs={'pk': self.object.pk})
|
|
#
|
|
# def form_invalid(self, form):
|
|
# """Handle form validation errors."""
|
|
# messages.error(
|
|
# self.request,
|
|
# _('There was an error updating the notification. Please check the form.')
|
|
# )
|
|
# return super().form_invalid(form)
|
|
#
|
|
#
|
|
# class SystemNotificationDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
|
|
# """View for deleting a system notification."""
|
|
# model = SystemNotification
|
|
# template_name = 'core/system_notification_confirm_delete.html'
|
|
# permission_required = 'core.delete_systemnotification'
|
|
#
|
|
# def get_queryset(self):
|
|
# """Filter by user's tenant if not superuser."""
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# if not user.is_superuser:
|
|
# if hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(tenant=user.tenant)
|
|
# else:
|
|
# queryset = queryset.none()
|
|
#
|
|
# return queryset
|
|
#
|
|
# def delete(self, request, *args, **kwargs):
|
|
# """Override delete to log the action."""
|
|
# self.object = self.get_object()
|
|
# title = self.object.title
|
|
#
|
|
# # Log the action before deletion
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='DELETE',
|
|
# content_object=self.object,
|
|
# request=request
|
|
# )
|
|
#
|
|
# # Proceed with deletion
|
|
# self.object.delete()
|
|
#
|
|
# messages.success(
|
|
# request,
|
|
# _('Notification "{}" was deleted successfully.').format(title)
|
|
# )
|
|
#
|
|
# # Return to notification list
|
|
# return HttpResponseRedirect(reverse('core:system_notification_list'))
|
|
#
|
|
#
|
|
# class IntegrationLogListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
|
# """View for listing integration logs."""
|
|
# model = IntegrationLog
|
|
# template_name = 'core/integration_log_list.html'
|
|
# context_object_name = 'logs'
|
|
# paginate_by = 50
|
|
# permission_required = 'core.view_integrationlog'
|
|
#
|
|
# def get_queryset(self):
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# # Filter by tenant for non-superusers
|
|
# if not user.is_superuser:
|
|
# if hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(tenant=user.tenant)
|
|
# else:
|
|
# queryset = queryset.filter(tenant__isnull=True)
|
|
#
|
|
# # Get form data
|
|
# form = IntegrationLogFilterForm(
|
|
# self.request.GET,
|
|
# tenant=getattr(user, 'tenant', None)
|
|
# )
|
|
#
|
|
# if form.is_valid():
|
|
# # Apply filters
|
|
# integration_name = form.cleaned_data.get('integration_name')
|
|
# if integration_name:
|
|
# queryset = queryset.filter(integration_name=integration_name)
|
|
#
|
|
# event_type = form.cleaned_data.get('event_type')
|
|
# if event_type:
|
|
# queryset = queryset.filter(event_type=event_type)
|
|
#
|
|
# status = form.cleaned_data.get('status')
|
|
# if status:
|
|
# queryset = queryset.filter(status=status)
|
|
#
|
|
# direction = form.cleaned_data.get('direction')
|
|
# if direction:
|
|
# queryset = queryset.filter(direction=direction)
|
|
#
|
|
# date_from = form.cleaned_data.get('date_from')
|
|
# if date_from:
|
|
# queryset = queryset.filter(timestamp__gte=date_from)
|
|
#
|
|
# date_to = form.cleaned_data.get('date_to')
|
|
# if date_to:
|
|
# queryset = queryset.filter(timestamp__lte=date_to)
|
|
#
|
|
# correlation_id = form.cleaned_data.get('correlation_id')
|
|
# if correlation_id:
|
|
# queryset = queryset.filter(correlation_id=correlation_id)
|
|
#
|
|
# return queryset.select_related('tenant', 'user').order_by('-timestamp')
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
#
|
|
# # Add filter form
|
|
# context['filter_form'] = IntegrationLogFilterForm(
|
|
# self.request.GET,
|
|
# tenant=getattr(self.request.user, 'tenant', None)
|
|
# )
|
|
#
|
|
# # Integration success rates
|
|
# logs = context['logs']
|
|
# integrations = {}
|
|
#
|
|
# for log in logs:
|
|
# name = log.integration_name
|
|
# if name not in integrations:
|
|
# integrations[name] = {'success': 0, 'total': 0}
|
|
#
|
|
# integrations[name]['total'] += 1
|
|
# if log.status == 'SUCCESS':
|
|
# integrations[name]['success'] += 1
|
|
#
|
|
# for name, data in integrations.items():
|
|
# if data['total'] > 0:
|
|
# data['success_rate'] = (data['success'] / data['total']) * 100
|
|
# else:
|
|
# data['success_rate'] = 0
|
|
#
|
|
# context['integrations'] = integrations
|
|
#
|
|
# return context
|
|
#
|
|
#
|
|
# class IntegrationLogDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
|
# """View for displaying integration log details."""
|
|
# model = IntegrationLog
|
|
# template_name = 'core/integration_log_detail.html'
|
|
# context_object_name = 'log'
|
|
# permission_required = 'core.view_integrationlog'
|
|
#
|
|
# def get_queryset(self):
|
|
# """Filter by user's tenant if not superuser."""
|
|
# queryset = super().get_queryset()
|
|
# user = self.request.user
|
|
#
|
|
# if not user.is_superuser:
|
|
# if hasattr(user, 'tenant') and user.tenant:
|
|
# queryset = queryset.filter(tenant=user.tenant)
|
|
# else:
|
|
# queryset = queryset.filter(tenant__isnull=True)
|
|
#
|
|
# return queryset.select_related('tenant', 'user', 'related_object_type')
|
|
#
|
|
# def get_context_data(self, **kwargs):
|
|
# context = super().get_context_data(**kwargs)
|
|
# log = self.get_object()
|
|
#
|
|
# # Get related logs with same correlation ID
|
|
# if log.correlation_id:
|
|
# context['related_logs'] = IntegrationLog.objects.filter(
|
|
# correlation_id=log.correlation_id
|
|
# ).exclude(pk=log.pk).order_by('-timestamp')
|
|
#
|
|
# # Format request/response data for better display
|
|
# if log.request_data:
|
|
# try:
|
|
# context['formatted_request'] = json.dumps(log.request_data, indent=2)
|
|
# except:
|
|
# context['formatted_request'] = str(log.request_data)
|
|
#
|
|
# if log.response_data:
|
|
# try:
|
|
# context['formatted_response'] = json.dumps(log.response_data, indent=2)
|
|
# except:
|
|
# context['formatted_response'] = str(log.response_data)
|
|
#
|
|
# # Get related object if available
|
|
# if log.related_object_type and log.related_object_id:
|
|
# try:
|
|
# model_class = log.related_object_type.model_class()
|
|
# context['related_object'] = model_class.objects.filter(
|
|
# pk=log.related_object_id
|
|
# ).first()
|
|
# except:
|
|
# context['related_object'] = None
|
|
#
|
|
# return context
|
|
#
|
|
#
|
|
# @login_required
|
|
# @permission_required('core.view_systemnotification')
|
|
# def dashboard_stats(request):
|
|
# """API endpoint for dashboard statistics."""
|
|
# user = request.user
|
|
# tenant = getattr(user, 'tenant', None)
|
|
#
|
|
# # Default to last 30 days for stats
|
|
# thirty_days_ago = timezone.now() - timezone.timedelta(days=30)
|
|
#
|
|
# # Basic system stats
|
|
# stats = {
|
|
# 'tenant_count': Tenant.objects.filter(is_active=True).count(),
|
|
# 'department_count': Department.objects.count(),
|
|
# 'active_notifications': SystemNotification.objects.filter(
|
|
# is_active=True,
|
|
# start_date__lte=timezone.now(),
|
|
# ).count(),
|
|
# }
|
|
#
|
|
# # Audit log stats
|
|
# if user.is_superuser:
|
|
# log_base_query = AuditLogEntry.objects
|
|
# elif tenant:
|
|
# log_base_query = AuditLogEntry.objects.filter(tenant=tenant)
|
|
# else:
|
|
# log_base_query = AuditLogEntry.objects.none()
|
|
#
|
|
# audit_logs = log_base_query.filter(timestamp__gte=thirty_days_ago)
|
|
#
|
|
# stats['audit_logs'] = {
|
|
# 'total': audit_logs.count(),
|
|
# 'by_action': dict(audit_logs.values('action_type').annotate(
|
|
# count=Count('action_type')
|
|
# ).values_list('action_type', 'count'))
|
|
# }
|
|
#
|
|
# # Integration stats
|
|
# if user.is_superuser or (user.is_staff and user.has_perm('core.view_integrationlog')):
|
|
# if tenant:
|
|
# integration_base_query = IntegrationLog.objects.filter(tenant=tenant)
|
|
# else:
|
|
# integration_base_query = IntegrationLog.objects
|
|
#
|
|
# integration_logs = integration_base_query.filter(timestamp__gte=thirty_days_ago)
|
|
#
|
|
# stats['integrations'] = {
|
|
# 'total': integration_logs.count(),
|
|
# 'success_count': integration_logs.filter(status='SUCCESS').count(),
|
|
# 'error_count': integration_logs.filter(status='ERROR').count(),
|
|
# 'by_status': dict(integration_logs.values('status').annotate(
|
|
# count=Count('status')
|
|
# ).values_list('status', 'count'))
|
|
# }
|
|
#
|
|
# return JsonResponse({'status': 'success', 'data': stats})
|
|
#
|
|
#
|
|
# @login_required
|
|
# @permission_required('core.view_auditlogentry')
|
|
# def audit_log_search(request):
|
|
# """API endpoint for searching audit logs."""
|
|
# user = request.user
|
|
# tenant = getattr(user, 'tenant', None)
|
|
#
|
|
# # Get search parameters
|
|
# search_term = request.GET.get('term', '')
|
|
# action_type = request.GET.get('action_type', '')
|
|
# date_from = request.GET.get('date_from', '')
|
|
# date_to = request.GET.get('date_to', '')
|
|
#
|
|
# # Base query
|
|
# if user.is_superuser:
|
|
# query = AuditLogEntry.objects.all()
|
|
# elif tenant:
|
|
# query = AuditLogEntry.objects.filter(tenant=tenant)
|
|
# else:
|
|
# query = AuditLogEntry.objects.none()
|
|
#
|
|
# # Apply filters
|
|
# if search_term:
|
|
# query = query.filter(
|
|
# Q(username__icontains=search_term) |
|
|
# Q(object_repr__icontains=search_term) |
|
|
# Q(ip_address__icontains=search_term)
|
|
# )
|
|
#
|
|
# if action_type:
|
|
# query = query.filter(action_type=action_type)
|
|
#
|
|
# if date_from:
|
|
# query = query.filter(timestamp__date__gte=date_from)
|
|
#
|
|
# if date_to:
|
|
# query = query.filter(timestamp__date__lte=date_to)
|
|
#
|
|
# # Get results
|
|
# results = query.order_by('-timestamp')[:100]
|
|
#
|
|
# # Format results
|
|
# formatted_results = [{
|
|
# 'id': str(log.log_id),
|
|
# 'user': log.username,
|
|
# 'action': log.get_action_type_display(),
|
|
# 'object': log.object_repr,
|
|
# 'timestamp': log.timestamp.isoformat(),
|
|
# 'url': reverse('core:audit_log_detail', args=[log.log_id])
|
|
# } for log in results]
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'results': formatted_results,
|
|
# 'count': len(formatted_results)
|
|
# })
|
|
#
|
|
#
|
|
# @login_required
|
|
# def system_notifications(request):
|
|
# """API endpoint for getting active system notifications for the current user."""
|
|
# user = request.user
|
|
#
|
|
# # Get active notifications
|
|
# active_notifications = SystemNotification.objects.filter(
|
|
# is_active=True,
|
|
# start_date__lte=timezone.now(),
|
|
# )
|
|
#
|
|
# # Filter to show relevant notifications to this user
|
|
# user_notifications = []
|
|
# for notification in active_notifications:
|
|
# if notification.is_visible_to_user(user):
|
|
# user_notifications.append({
|
|
# 'id': str(notification.notification_id),
|
|
# 'title': notification.title,
|
|
# 'message': notification.message,
|
|
# 'type': notification.notification_type,
|
|
# 'is_dismissible': notification.is_dismissible,
|
|
# 'link_url': notification.link_url,
|
|
# 'link_text': notification.link_text
|
|
# })
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'notifications': user_notifications
|
|
# })
|
|
#
|
|
#
|
|
# @login_required
|
|
# @require_POST
|
|
# @csrf_protect
|
|
# def dismiss_notification(request):
|
|
# """API endpoint for dismissing a notification."""
|
|
# form = NotificationDismissForm(request.POST)
|
|
#
|
|
# if form.is_valid():
|
|
# notification_id = form.cleaned_data['notification_id']
|
|
#
|
|
# try:
|
|
# notification = SystemNotification.objects.get(notification_id=notification_id)
|
|
#
|
|
# # Check if notification is dismissible
|
|
# if not notification.is_dismissible:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('This notification cannot be dismissed.')
|
|
# }, status=400)
|
|
#
|
|
# # Check if already dismissed
|
|
# if NotificationDismissal.objects.filter(
|
|
# notification=notification,
|
|
# user=request.user
|
|
# ).exists():
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'message': _('Notification already dismissed.')
|
|
# })
|
|
#
|
|
# # Create dismissal record
|
|
# dismissal = NotificationDismissal.objects.create(
|
|
# notification=notification,
|
|
# user=request.user
|
|
# )
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='OTHER',
|
|
# content_object=dismissal,
|
|
# action_details={'action': 'notification_dismissed'},
|
|
# request=request
|
|
# )
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'message': _('Notification dismissed successfully.')
|
|
# })
|
|
#
|
|
# except SystemNotification.DoesNotExist:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('Notification not found.')
|
|
# }, status=404)
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('Invalid form data.'),
|
|
# 'errors': form.errors
|
|
# }, status=400)
|
|
#
|
|
#
|
|
# @login_required
|
|
# def tenant_info(request):
|
|
# """API endpoint for getting information about the current user's tenant."""
|
|
# user = request.user
|
|
# tenant = getattr(user, 'tenant', None)
|
|
#
|
|
# if not tenant:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('No tenant associated with this user.')
|
|
# }, status=404)
|
|
#
|
|
# tenant_data = {
|
|
# 'id': str(tenant.tenant_id),
|
|
# 'name': tenant.name,
|
|
# 'code': tenant.code,
|
|
# 'organization_type': tenant.get_organization_type_display(),
|
|
# 'is_active': tenant.is_active,
|
|
# 'subscription_valid': tenant.is_subscription_valid(),
|
|
# 'department_count': tenant.departments.count(),
|
|
# 'active_users_count': tenant.get_active_users_count()
|
|
# }
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'tenant': tenant_data
|
|
# })
|
|
#
|
|
#
|
|
# @login_required
|
|
# @permission_required('core.view_integrationlog')
|
|
# def system_health(request):
|
|
# """API endpoint for system health information."""
|
|
# user = request.user
|
|
# tenant = getattr(user, 'tenant', None)
|
|
#
|
|
# # Default to last 7 days for stats
|
|
# days = int(request.GET.get('days', 7))
|
|
# period_start = timezone.now() - timezone.timedelta(days=days)
|
|
#
|
|
# # Base health data
|
|
# health_data = {
|
|
# 'tenants': {
|
|
# 'active': Tenant.objects.filter(is_active=True).count(),
|
|
# 'inactive': Tenant.objects.filter(is_active=False).count(),
|
|
# },
|
|
# 'departments': Department.objects.count(),
|
|
# }
|
|
#
|
|
# # Integration health
|
|
# if user.is_superuser:
|
|
# integration_base_query = IntegrationLog.objects
|
|
# elif tenant:
|
|
# integration_base_query = IntegrationLog.objects.filter(tenant=tenant)
|
|
# else:
|
|
# integration_base_query = IntegrationLog.objects.none()
|
|
#
|
|
# integration_logs = integration_base_query.filter(timestamp__gte=period_start)
|
|
# integration_stats = {
|
|
# 'total': integration_logs.count(),
|
|
# 'success': integration_logs.filter(status='SUCCESS').count(),
|
|
# 'error': integration_logs.filter(status='ERROR').count(),
|
|
# 'warning': integration_logs.filter(status='WARNING').count(),
|
|
# 'by_integration': {}
|
|
# }
|
|
#
|
|
# # Get stats by integration
|
|
# integrations = integration_logs.values('integration_name').distinct()
|
|
# for integration in integrations:
|
|
# name = integration['integration_name']
|
|
# logs = integration_logs.filter(integration_name=name)
|
|
#
|
|
# total = logs.count()
|
|
# success = logs.filter(status='SUCCESS').count()
|
|
#
|
|
# integration_stats['by_integration'][name] = {
|
|
# 'total': total,
|
|
# 'success': success,
|
|
# 'error': logs.filter(status='ERROR').count(),
|
|
# 'success_rate': (success / total * 100) if total > 0 else 0
|
|
# }
|
|
#
|
|
# health_data['integrations'] = integration_stats
|
|
#
|
|
# # Recent system errors
|
|
# if user.is_superuser:
|
|
# recent_errors = IntegrationLog.objects.filter(
|
|
# status='ERROR',
|
|
# timestamp__gte=period_start
|
|
# ).order_by('-timestamp')[:10]
|
|
# elif tenant:
|
|
# recent_errors = IntegrationLog.objects.filter(
|
|
# tenant=tenant,
|
|
# status='ERROR',
|
|
# timestamp__gte=period_start
|
|
# ).order_by('-timestamp')[:10]
|
|
# else:
|
|
# recent_errors = IntegrationLog.objects.none()
|
|
#
|
|
# health_data['recent_errors'] = [{
|
|
# 'id': str(log.log_id),
|
|
# 'integration': log.integration_name,
|
|
# 'event_type': log.event_type,
|
|
# 'timestamp': log.timestamp.isoformat(),
|
|
# 'error_message': log.error_message,
|
|
# 'url': reverse('core:integration_log_detail', args=[log.log_id])
|
|
# } for log in recent_errors]
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'data': health_data
|
|
# })
|
|
#
|
|
#
|
|
# @login_required
|
|
# @permission_required('core.change_systemnotification')
|
|
# @require_POST
|
|
# @csrf_protect
|
|
# def activate_notification(request, pk):
|
|
# """Activate a system notification."""
|
|
# try:
|
|
# notification = SystemNotification.objects.get(pk=pk)
|
|
#
|
|
# # Check permissions for tenant-specific notifications
|
|
# user = request.user
|
|
# tenant = getattr(user, 'tenant', None)
|
|
#
|
|
# if not user.is_superuser and notification.tenant and notification.tenant != tenant:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('You do not have permission to modify this notification.')
|
|
# }, status=403)
|
|
#
|
|
# # Activate the notification
|
|
# notification.is_active = True
|
|
# notification.save()
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='UPDATE',
|
|
# content_object=notification,
|
|
# changes={'is_active': {'old': 'False', 'new': 'True'}},
|
|
# request=request
|
|
# )
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'message': _('Notification activated successfully.')
|
|
# })
|
|
#
|
|
# except SystemNotification.DoesNotExist:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('Notification not found.')
|
|
# }, status=404)
|
|
#
|
|
#
|
|
# @login_required
|
|
# @permission_required('core.change_systemnotification')
|
|
# @require_POST
|
|
# @csrf_protect
|
|
# def deactivate_notification(request, pk):
|
|
# """Deactivate a system notification."""
|
|
# try:
|
|
# notification = SystemNotification.objects.get(pk=pk)
|
|
#
|
|
# # Check permissions for tenant-specific notifications
|
|
# user = request.user
|
|
# tenant = getattr(user, 'tenant', None)
|
|
#
|
|
# if not user.is_superuser and notification.tenant and notification.tenant != tenant:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('You do not have permission to modify this notification.')
|
|
# }, status=403)
|
|
#
|
|
# # Deactivate the notification
|
|
# notification.is_active = False
|
|
# notification.save()
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='UPDATE',
|
|
# content_object=notification,
|
|
# changes={'is_active': {'old': 'True', 'new': 'False'}},
|
|
# request=request
|
|
# )
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'message': _('Notification deactivated successfully.')
|
|
# })
|
|
#
|
|
# except SystemNotification.DoesNotExist:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('Notification not found.')
|
|
# }, status=404)
|
|
#
|
|
#
|
|
# @login_required
|
|
# @permission_required('core.change_systemconfiguration')
|
|
# @require_POST
|
|
# @csrf_protect
|
|
# def reset_configuration(request, pk):
|
|
# """Reset a system configuration to its default value."""
|
|
# try:
|
|
# config = SystemConfiguration.objects.get(pk=pk)
|
|
#
|
|
# # Check permissions for tenant-specific configurations
|
|
# user = request.user
|
|
# tenant = getattr(user, 'tenant', None)
|
|
#
|
|
# if not user.is_superuser:
|
|
# if config.tenant and config.tenant != tenant:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('You do not have permission to modify this configuration.')
|
|
# }, status=403)
|
|
#
|
|
# if not config.is_tenant_editable:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('This configuration cannot be modified by tenant users.')
|
|
# }, status=403)
|
|
#
|
|
# # Get the default value
|
|
# old_value = config.value
|
|
#
|
|
# # For tenant-specific configurations, try to get the system-wide value
|
|
# if config.tenant:
|
|
# try:
|
|
# system_config = SystemConfiguration.objects.get(
|
|
# key=config.key,
|
|
# tenant=None
|
|
# )
|
|
# config.value = system_config.value
|
|
# config.save()
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='UPDATE',
|
|
# content_object=config,
|
|
# changes={'value': {'old': old_value, 'new': config.value}},
|
|
# request=request
|
|
# )
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'message': _('Configuration reset to system default successfully.'),
|
|
# 'new_value': config.value
|
|
# })
|
|
#
|
|
# except SystemConfiguration.DoesNotExist:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('No system-wide default value found for this configuration.')
|
|
# }, status=404)
|
|
#
|
|
# # For system-wide configurations, this operation doesn't make sense
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('System-wide configurations cannot be reset to defaults.')
|
|
# }, status=400)
|
|
#
|
|
# except SystemConfiguration.DoesNotExist:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('Configuration not found.')
|
|
# }, status=404)
|
|
|
|
|
|
|
|
|
|
|
|
# @login_required
|
|
# def department_search(request):
|
|
# """API endpoint for searching departments."""
|
|
# user = request.user
|
|
# tenant = getattr(user, 'tenant', None)
|
|
#
|
|
# # Get search parameters
|
|
# search_term = request.GET.get('term', '')
|
|
# department_type = request.GET.get('department_type', '')
|
|
# is_active = request.GET.get('is_active', '')
|
|
#
|
|
# # Base query
|
|
# if user.is_superuser:
|
|
# query = Department.objects.all()
|
|
# elif tenant:
|
|
# query = Department.objects.filter(tenant=tenant)
|
|
# else:
|
|
# query = Department.objects.none()
|
|
#
|
|
# # Apply filters
|
|
# if search_term:
|
|
# query = query.filter(
|
|
# Q(name__icontains=search_term) |
|
|
# Q(code__icontains=search_term) |
|
|
# Q(description__icontains=search_term)
|
|
# )
|
|
#
|
|
# if department_type:
|
|
# query = query.filter(department_type=department_type)
|
|
#
|
|
# if is_active:
|
|
# is_active_bool = is_active.lower() == 'true'
|
|
# query = query.filter(is_active=is_active_bool)
|
|
#
|
|
# # Get results
|
|
# results = query.order_by('name')[:20]
|
|
#
|
|
# # Format results
|
|
# formatted_results = [{
|
|
# 'id': str(department.department_id),
|
|
# 'name': department.name,
|
|
# 'code': department.code,
|
|
# 'type': department.get_department_type_display(),
|
|
# 'is_active': department.is_active,
|
|
# 'department_head': department.department_head.get_full_name() if department.department_head else None,
|
|
# 'location': department.get_full_location(),
|
|
# 'url': reverse('core:department_detail', args=[department.department_id])
|
|
# } for department in results]
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'results': formatted_results,
|
|
# 'count': len(formatted_results)
|
|
# })
|
|
#
|
|
#
|
|
# @login_required
|
|
# @permission_required('core.change_tenant')
|
|
# @require_POST
|
|
# @csrf_protect
|
|
# def activate_tenant(request, pk):
|
|
# """Activate a tenant."""
|
|
# try:
|
|
# tenant = Tenant.objects.get(pk=pk)
|
|
#
|
|
# # Only superusers can activate any tenant
|
|
# if not request.user.is_superuser:
|
|
# user_tenant = getattr(request.user, 'tenant', None)
|
|
# if tenant != user_tenant:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('You do not have permission to modify this tenant.')
|
|
# }, status=403)
|
|
#
|
|
# # Activate the tenant
|
|
# if tenant.is_active:
|
|
# return JsonResponse({
|
|
# 'status': 'info',
|
|
# 'message': _('Tenant is already active.')
|
|
# })
|
|
#
|
|
# tenant.is_active = True
|
|
# tenant.save()
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='UPDATE',
|
|
# content_object=tenant,
|
|
# changes={'is_active': {'old': 'False', 'new': 'True'}},
|
|
# request=request
|
|
# )
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'message': _('Tenant activated successfully.')
|
|
# })
|
|
#
|
|
# except Tenant.DoesNotExist:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('Tenant not found.')
|
|
# }, status=404)
|
|
#
|
|
#
|
|
# @login_required
|
|
# @permission_required('core.change_tenant')
|
|
# @require_POST
|
|
# @csrf_protect
|
|
# def deactivate_tenant(request, pk):
|
|
# """Deactivate a tenant."""
|
|
# try:
|
|
# tenant = Tenant.objects.get(pk=pk)
|
|
#
|
|
# # Only superusers can deactivate any tenant
|
|
# if not request.user.is_superuser:
|
|
# user_tenant = getattr(request.user, 'tenant', None)
|
|
# if tenant != user_tenant:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('You do not have permission to modify this tenant.')
|
|
# }, status=403)
|
|
#
|
|
# # Prevent deactivating your own tenant
|
|
# if tenant == getattr(request.user, 'tenant', None):
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('You cannot deactivate your own tenant.')
|
|
# }, status=400)
|
|
#
|
|
# # Deactivate the tenant
|
|
# if not tenant.is_active:
|
|
# return JsonResponse({
|
|
# 'status': 'info',
|
|
# 'message': _('Tenant is already inactive.')
|
|
# })
|
|
#
|
|
# tenant.is_active = False
|
|
# tenant.save()
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='UPDATE',
|
|
# content_object=tenant,
|
|
# changes={'is_active': {'old': 'True', 'new': 'False'}},
|
|
# request=request
|
|
# )
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'message': _('Tenant deactivated successfully.')
|
|
# })
|
|
#
|
|
# except Tenant.DoesNotExist:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('Tenant not found.')
|
|
# }, status=404)
|
|
#
|
|
#
|
|
# @login_required
|
|
# @permission_required('core.change_department')
|
|
# @require_POST
|
|
# @csrf_protect
|
|
# def activate_department(request, pk):
|
|
# """Activate a department."""
|
|
# try:
|
|
# department = Department.objects.get(pk=pk)
|
|
#
|
|
# # Check permissions
|
|
# user = request.user
|
|
# tenant = getattr(user, 'tenant', None)
|
|
#
|
|
# if not user.is_superuser and department.tenant != tenant:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('You do not have permission to modify this department.')
|
|
# }, status=403)
|
|
#
|
|
# # Activate the department
|
|
# if department.is_active:
|
|
# return JsonResponse({
|
|
# 'status': 'info',
|
|
# 'message': _('Department is already active.')
|
|
# })
|
|
#
|
|
# department.is_active = True
|
|
# department.save()
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='UPDATE',
|
|
# content_object=department,
|
|
# changes={'is_active': {'old': 'False', 'new': 'True'}},
|
|
# request=request
|
|
# )
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'message': _('Department activated successfully.')
|
|
# })
|
|
#
|
|
# except Department.DoesNotExist:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('Department not found.')
|
|
# }, status=404)
|
|
#
|
|
#
|
|
# @login_required
|
|
# @permission_required('core.change_department')
|
|
# @require_POST
|
|
# @csrf_protect
|
|
# def deactivate_department(request, pk):
|
|
# """Deactivate a department."""
|
|
# try:
|
|
# department = Department.objects.get(pk=pk)
|
|
#
|
|
# # Check permissions
|
|
# user = request.user
|
|
# tenant = getattr(user, 'tenant', None)
|
|
#
|
|
# if not user.is_superuser and department.tenant != tenant:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('You do not have permission to modify this department.')
|
|
# }, status=403)
|
|
#
|
|
# # Check if this is the user's department
|
|
# if hasattr(user, 'department') and user.department == department:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('You cannot deactivate your own department.')
|
|
# }, status=400)
|
|
#
|
|
# # Deactivate the department
|
|
# if not department.is_active:
|
|
# return JsonResponse({
|
|
# 'status': 'info',
|
|
# 'message': _('Department is already inactive.')
|
|
# })
|
|
#
|
|
# department.is_active = False
|
|
# department.save()
|
|
#
|
|
# # Log the action
|
|
# AuditLogEntry.log_action(
|
|
# user=request.user,
|
|
# action_type='UPDATE',
|
|
# content_object=department,
|
|
# changes={'is_active': {'old': 'True', 'new': 'False'}},
|
|
# request=request
|
|
# )
|
|
#
|
|
# return JsonResponse({
|
|
# 'status': 'success',
|
|
# 'message': _('Department deactivated successfully.')
|
|
# })
|
|
#
|
|
# except Department.DoesNotExist:
|
|
# return JsonResponse({
|
|
# 'status': 'error',
|
|
# 'message': _('Department not found.')
|
|
# }, status=404)
|
|
#
|