160 lines
6.2 KiB
Python
160 lines
6.2 KiB
Python
from datetime import timedelta
|
|
|
|
from django.contrib import messages
|
|
from django.db.models import Count, Q
|
|
from django.shortcuts import redirect, render
|
|
from django.utils import timezone
|
|
from django.utils.translation import gettext as _
|
|
|
|
from .backup_ops import create_backup_bundle, latest_backup_health_snapshot, list_backup_bundles, verify_backup_bundle
|
|
from .models import AdminAuditLog, AsyncTaskLog, UserNotification, UserProfile
|
|
from .roles import user_has_capability
|
|
|
|
|
|
def job_monitor_page_impl(request):
|
|
status_filter = (request.GET.get('status') or '').strip()
|
|
task_filter = (request.GET.get('task') or '').strip()
|
|
logs = AsyncTaskLog.objects.all()
|
|
if status_filter:
|
|
logs = logs.filter(status=status_filter)
|
|
if task_filter:
|
|
logs = logs.filter(task_name=task_filter)
|
|
logs = logs.order_by('-started_at', '-id')[:200]
|
|
task_names = list(AsyncTaskLog.objects.order_by('task_name').values_list('task_name', flat=True).distinct())
|
|
since = timezone.now() - timedelta(hours=24)
|
|
recent_logs = AsyncTaskLog.objects.filter(started_at__gte=since)
|
|
counts = {row['status']: row['count'] for row in recent_logs.values('status').annotate(count=Count('id'))}
|
|
recent_failed = list(AsyncTaskLog.objects.filter(status='failed').order_by('-started_at', '-id')[:5])
|
|
can_manage_backups = user_has_capability(request.user, 'manage_backups')
|
|
return render(
|
|
request,
|
|
'workflows/job_monitor.html',
|
|
{
|
|
'logs': logs,
|
|
'status_filter': status_filter,
|
|
'task_filter': task_filter,
|
|
'task_names': task_names,
|
|
'status_choices': [('started', _('Gestartet')), ('succeeded', _('Erfolgreich')), ('failed', _('Fehlgeschlagen'))],
|
|
'job_summary': {
|
|
'started_count_24h': counts.get('started', 0),
|
|
'success_count_24h': counts.get('succeeded', 0),
|
|
'failed_count_24h': counts.get('failed', 0),
|
|
'recent_failed': recent_failed,
|
|
'can_manage_backups': can_manage_backups,
|
|
'backup_health': latest_backup_health_snapshot() if can_manage_backups else None,
|
|
},
|
|
},
|
|
)
|
|
|
|
|
|
def audit_log_page_impl(request):
|
|
action = (request.GET.get('action') or '').strip()
|
|
user_query = (request.GET.get('user') or '').strip()
|
|
date_from = (request.GET.get('date_from') or '').strip()
|
|
date_to = (request.GET.get('date_to') or '').strip()
|
|
|
|
rows_qs = AdminAuditLog.objects.select_related('actor').all()
|
|
if action:
|
|
rows_qs = rows_qs.filter(action=action)
|
|
if user_query:
|
|
rows_qs = rows_qs.filter(
|
|
Q(actor_display__icontains=user_query)
|
|
| Q(actor__username__icontains=user_query)
|
|
| Q(actor__email__icontains=user_query)
|
|
)
|
|
if date_from:
|
|
rows_qs = rows_qs.filter(created_at__date__gte=date_from)
|
|
if date_to:
|
|
rows_qs = rows_qs.filter(created_at__date__lte=date_to)
|
|
|
|
rows = list(rows_qs[:300])
|
|
action_choices = AdminAuditLog.objects.order_by('action').values_list('action', flat=True).distinct()
|
|
return render(
|
|
request,
|
|
'workflows/audit_log.html',
|
|
{
|
|
'rows': rows,
|
|
'action_choices': action_choices,
|
|
'selected_action': action,
|
|
'user_query': user_query,
|
|
'date_from': date_from,
|
|
'date_to': date_to,
|
|
},
|
|
)
|
|
|
|
|
|
def backup_recovery_page_impl(request):
|
|
rows = list_backup_bundles()
|
|
return render(
|
|
request,
|
|
'workflows/backup_recovery.html',
|
|
{
|
|
'rows': rows,
|
|
'backup_health': latest_backup_health_snapshot(),
|
|
},
|
|
)
|
|
|
|
|
|
def create_backup_from_admin_impl(request, *, audit_fn, notify_user_fn, create_backup_bundle_fn):
|
|
try:
|
|
result = create_backup_bundle_fn()
|
|
audit_fn(
|
|
request,
|
|
'backup_created',
|
|
target_type='backup_bundle',
|
|
target_label=result['name'],
|
|
details={'path': result['path']},
|
|
)
|
|
notify_user_fn(
|
|
user=request.user,
|
|
title=_('Backup erstellt: %(name)s') % {'name': result['name']},
|
|
body=_('Das Backup-Bundle wurde erfolgreich erstellt.'),
|
|
level=UserNotification.LEVEL_SUCCESS,
|
|
link_url='/admin-tools/backups/',
|
|
event_key=UserProfile.NOTIFICATION_BACKUP_SUCCESS,
|
|
)
|
|
messages.success(request, _('Backup wurde erstellt: %(name)s') % {'name': result['name']})
|
|
except Exception as exc:
|
|
notify_user_fn(
|
|
user=request.user,
|
|
title=_('Backup fehlgeschlagen'),
|
|
body=str(exc),
|
|
level=UserNotification.LEVEL_ERROR,
|
|
link_url='/admin-tools/backups/',
|
|
event_key=UserProfile.NOTIFICATION_BACKUP_FAILURE,
|
|
)
|
|
messages.error(request, _('Backup konnte nicht erstellt werden: %(error)s') % {'error': exc})
|
|
return redirect('backup_recovery_page')
|
|
|
|
|
|
def verify_backup_from_admin_impl(request, backup_name: str, *, audit_fn, notify_user_fn, verify_backup_bundle_fn):
|
|
try:
|
|
result = verify_backup_bundle_fn(backup_name)
|
|
audit_fn(
|
|
request,
|
|
'backup_verified',
|
|
target_type='backup_bundle',
|
|
target_label=backup_name,
|
|
details={'summary': result['summary']},
|
|
)
|
|
notify_user_fn(
|
|
user=request.user,
|
|
title=_('Backup verifiziert: %(name)s') % {'name': result['name']},
|
|
body=result.get('summary') or _('Das Backup wurde erfolgreich verifiziert.'),
|
|
level=UserNotification.LEVEL_SUCCESS,
|
|
link_url='/admin-tools/backups/',
|
|
event_key=UserProfile.NOTIFICATION_BACKUP_SUCCESS,
|
|
)
|
|
messages.success(request, _('Backup wurde verifiziert: %(name)s') % {'name': result['name']})
|
|
except Exception as exc:
|
|
notify_user_fn(
|
|
user=request.user,
|
|
title=_('Backup-Verifikation fehlgeschlagen'),
|
|
body=str(exc),
|
|
level=UserNotification.LEVEL_ERROR,
|
|
link_url='/admin-tools/backups/',
|
|
event_key=UserProfile.NOTIFICATION_BACKUP_FAILURE,
|
|
)
|
|
messages.error(request, _('Backup-Verifikation fehlgeschlagen: %(error)s') % {'error': exc})
|
|
return redirect('backup_recovery_page')
|