(feature) Add run completion notifications
Add email and webhook notification targets with delivery tracking, and send notifications when backup runs reach a terminal status. Expose notification target management in the Django UI and keep delivery failures recorded without failing the backup worker.
This commit is contained in:
@@ -32,13 +32,24 @@ from .forms import (
|
||||
HostConfigForm,
|
||||
IncompleteCleanupForm,
|
||||
ManualBackupForm,
|
||||
NotificationTargetForm,
|
||||
RetentionApplyForm,
|
||||
SshCredentialGenerateForm,
|
||||
ScheduleConfigForm,
|
||||
SshCredentialForm,
|
||||
)
|
||||
from .host_ops import ensure_host_directories
|
||||
from .models import BackupRun, GlobalConfig, HostConfig, PurgedSnapshot, ScheduleConfig, SnapshotRecord, SshCredential
|
||||
from .models import (
|
||||
BackupRun,
|
||||
GlobalConfig,
|
||||
HostConfig,
|
||||
NotificationDelivery,
|
||||
NotificationTarget,
|
||||
PurgedSnapshot,
|
||||
ScheduleConfig,
|
||||
SnapshotRecord,
|
||||
SshCredential,
|
||||
)
|
||||
from .preflight import collect_backup_gate, effective_host_config_preview, run_remote_preflight
|
||||
from .retention import run_incomplete_cleanup, run_sql_retention_apply, run_sql_retention_plan
|
||||
from .self_check import collect_self_checks, summarize_self_checks
|
||||
@@ -320,6 +331,65 @@ def logs(request):
|
||||
return render(request, "pobsync_backend/logs.html", context)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
def notification_targets(request):
|
||||
targets = NotificationTarget.objects.order_by("name")
|
||||
deliveries = NotificationDelivery.objects.select_related("target", "run", "run__host").order_by("-created_at")[:12]
|
||||
return render(
|
||||
request,
|
||||
"pobsync_backend/notification_targets.html",
|
||||
{
|
||||
"targets": targets,
|
||||
"deliveries": deliveries,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
def create_notification_target(request):
|
||||
if request.method == "POST":
|
||||
form = NotificationTargetForm(request.POST)
|
||||
if form.is_valid():
|
||||
target = form.save()
|
||||
messages.success(request, f"Notification target {target.name} created.")
|
||||
return redirect("notification_targets")
|
||||
else:
|
||||
form = NotificationTargetForm()
|
||||
return render(
|
||||
request,
|
||||
"pobsync_backend/notification_target_form.html",
|
||||
{
|
||||
"form": form,
|
||||
"target": None,
|
||||
"title": "New notification target",
|
||||
"submit_label": "Create target",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
def edit_notification_target(request, target_id: int):
|
||||
target = get_object_or_404(NotificationTarget, id=target_id)
|
||||
if request.method == "POST":
|
||||
form = NotificationTargetForm(request.POST, instance=target)
|
||||
if form.is_valid():
|
||||
target = form.save()
|
||||
messages.success(request, f"Notification target {target.name} updated.")
|
||||
return redirect("notification_targets")
|
||||
else:
|
||||
form = NotificationTargetForm(instance=target)
|
||||
return render(
|
||||
request,
|
||||
"pobsync_backend/notification_target_form.html",
|
||||
{
|
||||
"form": form,
|
||||
"target": target,
|
||||
"title": f"Edit notification target: {target.name}",
|
||||
"submit_label": "Save target",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@staff_member_required
|
||||
def runs_list(request):
|
||||
status = request.GET.get("status", "").strip()
|
||||
|
||||
Reference in New Issue
Block a user