diff --git a/dist/urbm-2026.06.21.r009-x86_64-1.txz.sha256 b/dist/urbm-2026.06.21.r009-x86_64-1.txz.sha256 deleted file mode 100644 index a9c9d07..0000000 --- a/dist/urbm-2026.06.21.r009-x86_64-1.txz.sha256 +++ /dev/null @@ -1 +0,0 @@ -7331dd7ade82aa68351b48f2555cd6dd9141620e6ba4ebce14e722fb0e6e5a46 urbm-2026.06.21.r009-x86_64-1.txz diff --git a/dist/urbm-2026.06.21.r009-x86_64-1.txz b/dist/urbm-2026.06.21.r010-x86_64-1.txz similarity index 55% rename from dist/urbm-2026.06.21.r009-x86_64-1.txz rename to dist/urbm-2026.06.21.r010-x86_64-1.txz index 35073ee..f6ad141 100644 Binary files a/dist/urbm-2026.06.21.r009-x86_64-1.txz and b/dist/urbm-2026.06.21.r010-x86_64-1.txz differ diff --git a/dist/urbm-2026.06.21.r010-x86_64-1.txz.sha256 b/dist/urbm-2026.06.21.r010-x86_64-1.txz.sha256 new file mode 100644 index 0000000..3d8562a --- /dev/null +++ b/dist/urbm-2026.06.21.r010-x86_64-1.txz.sha256 @@ -0,0 +1 @@ +6223df8fefd872c4e102a9dfadb8103bce4de364d2836b85d773591c92025c4b urbm-2026.06.21.r010-x86_64-1.txz diff --git a/dist/urbm.plg b/dist/urbm.plg index 510afff..3987555 100644 --- a/dist/urbm.plg +++ b/dist/urbm.plg @@ -2,13 +2,17 @@ - + - + ]> +### 2026.06.21.r010 +- Enrich Unraid and Gotify notifications with structured job, repository, duration, snapshot, file, and data statistics. +- Use status-specific notification titles with success, warning, and failure indicators. + ### 2026.06.21.r009 - Allow normal staging restores to explicitly selected safe targets under /mnt/user, /mnt/disks, and /mnt/remotes. - Keep protected system paths blocked and continue rejecting symlink traversal in restore targets. diff --git a/internal/service/notification_test.go b/internal/service/notification_test.go index 292a27b..32a93c8 100644 --- a/internal/service/notification_test.go +++ b/internal/service/notification_test.go @@ -12,10 +12,18 @@ func TestNotificationMessageIncludesBackupStatistics(t *testing.T) { started := time.Date(2026, 6, 14, 12, 0, 0, 0, time.UTC) finished := started.Add(2*time.Minute + 8*time.Second) run := model.Run{TaskType: "backup", Status: "success", StartedAt: &started, FinishedAt: &finished, SnapshotID: "abc123", BytesAdded: 1536, FilesNew: 7, FilesChanged: 2, BytesProcessed: 5 * 1024 * 1024, FilesProcessed: 120} - message := notificationMessage(run, finished) - for _, expected := range []string{"Status: Erfolgreich", "Dauer: 2 Min. 8 Sek.", "Neu gespeichert: 1.5 KiB", "Neue Dateien: 7", "Geänderte Dateien: 2", "Gesamtgröße dieses Backups: 5.0 MiB", "Dateien insgesamt: 120", "Snapshot: abc123"} { + message := notificationMessage("Freigaben", "LV-426", run, finished) + for _, expected := range []string{"📊 URBM-Zusammenfassung", "Status: Erfolgreich", "Job: Freigaben", "Repository: LV-426", "Dauer: 2 Min. 8 Sek.", "Snapshot: abc123", "Verarbeitete Daten: 5.0 MiB", "Verarbeitete Dateien: 120", "Neu gespeichert: 1.5 KiB", "Neue Dateien: 7", "Geänderte Dateien: 2"} { if !strings.Contains(message, expected) { t.Errorf("message %q does not contain %q", message, expected) } } } + +func TestNotificationTitleIncludesRepositoryAndStatus(t *testing.T) { + run := model.Run{TaskType: "backup", Status: "failed"} + title := notificationTitle("Freigaben", "LV-426", run) + if title != "❌ URBM Backup: LV-426" { + t.Fatalf("title = %q", title) + } +} diff --git a/internal/service/service.go b/internal/service/service.go index 08206b7..72413c0 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -746,17 +746,24 @@ func (s *Service) executeRestore(ctx context.Context, run model.Run) model.Run { func (s *Service) finishJob(run model.Run, job model.Job, result model.Run) model.Run { if result.Status == "success" || result.Status == "warning" || result.Status == "failed" { - go s.notify(job.Name, result) + repoName := "" + if job.RepositoryID != "" { + if repo, ok := s.repository(job.RepositoryID); ok { + repoName = repo.Name + } + } + go s.notify(job.Name, repoName, result) } return result } -func (s *Service) notify(name string, run model.Run) { - message := notificationMessage(run, time.Now().UTC()) +func (s *Service) notify(name, repository string, run model.Run) { + title := notificationTitle(name, repository, run) + message := notificationMessage(name, repository, run, time.Now().UTC()) for _, target := range s.Config().Notifications { for _, event := range target.Events { if event == run.Status { - if err := s.notifier.Send(context.Background(), target, "URBM: "+name, message, run.Status); err != nil { + if err := s.notifier.Send(context.Background(), target, title, message, run.Status); err != nil { s.log.Warn("send notification failed", "target", target.ID, "type", target.Type, "error", err) } break @@ -765,12 +772,36 @@ func (s *Service) notify(name string, run model.Run) { } } -func notificationMessage(run model.Run, now time.Time) string { +func notificationTitle(name, repository string, run model.Run) string { + icon := map[string]string{"success": "✅", "warning": "⚠️", "failed": "❌"}[run.Status] + if icon == "" { + icon = "ℹ️" + } + task := map[string]string{"backup": "Backup", "rsync": "Rsync", "restore": "Restore", "check": "Prüfung", "prune": "Bereinigung"}[run.TaskType] + if task == "" { + task = run.TaskType + if task != "" { + task = strings.ToUpper(task[:1]) + task[1:] + } + } + if repository != "" { + return fmt.Sprintf("%s URBM %s: %s", icon, task, repository) + } + return fmt.Sprintf("%s URBM %s: %s", icon, task, name) +} + +func notificationMessage(name, repository string, run model.Run, now time.Time) string { status := map[string]string{"success": "Erfolgreich", "warning": "Mit Warnung", "failed": "Fehlgeschlagen"}[run.Status] if status == "" { status = run.Status } - lines := []string{"Status: " + status} + lines := []string{"📊 URBM-Zusammenfassung", "", "Status: " + status} + if name != "" { + lines = append(lines, "Job: "+name) + } + if repository != "" { + lines = append(lines, "Repository: "+repository) + } if run.StartedAt != nil { finished := now if run.FinishedAt != nil { @@ -781,16 +812,22 @@ func notificationMessage(run model.Run, now time.Time) string { } } if (run.TaskType == "backup" || run.TaskType == "rsync") && (run.Status == "success" || run.Status == "warning") { - lines = append(lines, - "Neu gespeichert: "+formatBytes(run.BytesAdded), - fmt.Sprintf("Neue Dateien: %d", run.FilesNew), - fmt.Sprintf("Geänderte Dateien: %d", run.FilesChanged), - "Gesamtgröße dieses Backups: "+formatBytes(run.BytesProcessed), - fmt.Sprintf("Dateien insgesamt: %d", run.FilesProcessed), - ) - if run.SnapshotID != "" { + if run.TaskType == "backup" && run.SnapshotID != "" { lines = append(lines, "Snapshot: "+run.SnapshotID) } + lines = append(lines, + "Verarbeitete Daten: "+formatBytes(run.BytesProcessed), + fmt.Sprintf("Verarbeitete Dateien: %d", run.FilesProcessed), + ) + if run.TaskType == "backup" { + lines = append(lines, + "Neu gespeichert: "+formatBytes(run.BytesAdded), + fmt.Sprintf("Neue Dateien: %d", run.FilesNew), + fmt.Sprintf("Geänderte Dateien: %d", run.FilesChanged), + ) + } else { + lines = append(lines, "Kopierte Daten: "+formatBytes(run.BytesAdded)) + } } if run.Message != "" && run.Message != "backup completed" && run.Message != "rsync completed" { lines = append(lines, "Details: "+run.Message) diff --git a/plugin/urbm.plg b/plugin/urbm.plg index af7f5b6..fe2016a 100644 --- a/plugin/urbm.plg +++ b/plugin/urbm.plg @@ -2,13 +2,17 @@ - + ]> +### 2026.06.21.r010 +- Enrich Unraid and Gotify notifications with structured job, repository, duration, snapshot, file, and data statistics. +- Use status-specific notification titles with success, warning, and failure indicators. + ### 2026.06.21.r009 - Allow normal staging restores to explicitly selected safe targets under /mnt/user, /mnt/disks, and /mnt/remotes. - Keep protected system paths blocked and continue rejecting symlink traversal in restore targets. diff --git a/webgui/URBM.page b/webgui/URBM.page index 6a66a8b..103f760 100644 --- a/webgui/URBM.page +++ b/webgui/URBM.page @@ -9,12 +9,12 @@ Tag="URBM Unraid Restic Backup Manager backup snapshots restore" - +
- -

URBM 2026.06.21.r009

Restic Backup Manager für Unraid

+ +

URBM 2026.06.21.r010

Restic Backup Manager für Unraid

Verbindung wird hergestellt...
@@ -32,4 +32,4 @@ $pluginRoot = '/plugins/urbm';
- +