From 08fef4872bbfd244774d738782a7fcccecb98ff6 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Wed, 15 Jul 2026 07:50:29 +0200 Subject: [PATCH] hub v0.55.0: accept offbox_enlarge_blocked event (Task 3a-fix delivery chain) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit allowedEventTypes gains offbox_enlarge_blocked (was 400 at ingestion, dropping the customer email). Deliberate NON-change: no customerMessages entry — the static map would discard the controller's dynamic two-number Hungarian message (templates.go:129 fallback is correct). event_test acceptance + 400 red-proof; templates_offbox_test locks the raw-message fallback. manifest bumped to :0.55.0. --- hub/CHANGELOG.md | 17 +++++++++++ hub/internal/api/event_test.go | 19 ++++++++++++ hub/internal/api/handler.go | 26 +++++++++------- hub/internal/notify/templates_offbox_test.go | 31 ++++++++++++++++++++ manifests/hub.yaml | 2 +- 5 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 hub/internal/notify/templates_offbox_test.go diff --git a/hub/CHANGELOG.md b/hub/CHANGELOG.md index 512d977..ca24208 100644 --- a/hub/CHANGELOG.md +++ b/hub/CHANGELOG.md @@ -1,5 +1,22 @@ # Felhom Hub — Changelog +## v0.55.0 — accept the offbox_enlarge_blocked event (Task 3a-fix delivery chain) (2026-07-15) + +The controller (v0.134.1) sends an `offbox_enlarge_blocked` warning when an app's enlarged offsite +push is refused by the quota gate (config+DB still saved). This closes the **ingestion** link of its +delivery chain. + +- **`internal/api/handler.go`:** `offbox_enlarge_blocked` added to `allowedEventTypes` — the event was + 400-rejected before (the customer email was dropped at ingestion). Acceptance case + + 400-red-proof added to `internal/api/event_test.go`. +- **Deliberate NON-change:** NO `customerMessages` entry. `FormatCustomerEmail` (`templates.go:129`) + gives the static per-type message PRIORITY over the raw message, so a static entry would DISCARD + the controller's dynamic two-number Hungarian text (estimate + quota). The documented fallback (raw + message survives) is the correct path; locked by a new `internal/notify/templates_offbox_test.go` + assertion. `internal/notify/dispatcher.go` and the customer `EnabledEvents` whitelist are unchanged + here — the controller side (v0.134.1) owns `DefaultEnabledEvents` + the prefs migration + the + settings checkbox. + ## v0.54.0 — operator login password changeable from the UI (2026-07-13) The hub login password was previously settable ONLY by editing the `auth.password_hash` field in diff --git a/hub/internal/api/event_test.go b/hub/internal/api/event_test.go index 385144a..ff5e869 100644 --- a/hub/internal/api/event_test.go +++ b/hub/internal/api/event_test.go @@ -78,6 +78,25 @@ func TestHandleEvent_UnknownEventTypeRejected(t *testing.T) { } } +// Scenario D (controller v0.134.1): offbox_enlarge_blocked is an accepted controller-pushed type — +// the enlarge-blocked notification's delivery chain starts at hub ingestion. Red-proof: removing the +// allowlist entry makes this 400 (the pre-fix behavior that dropped the customer email). +func TestHandleEvent_OffboxEnlargeBlockedAccepted(t *testing.T) { + h, st := newEventTestHandler(t) + + rr := do(h, http.MethodPost, "/event", "ckey", eventBody("warning", "offbox_enlarge_blocked")) + if rr.Code != http.StatusOK { + t.Fatalf("status = %d, want 200 (offbox_enlarge_blocked must be allowlisted); body=%s", rr.Code, rr.Body.String()) + } + evs, err := st.GetRecentEvents("c1", 10) + if err != nil { + t.Fatalf("GetRecentEvents: %v", err) + } + if len(evs) != 1 || evs[0].EventType != "offbox_enlarge_blocked" { + t.Errorf("stored = %+v, want exactly one offbox_enlarge_blocked event", evs) + } +} + // Auth: no bearer at all is a 401 and stores nothing. func TestHandleEvent_Unauthorized(t *testing.T) { h, st := newEventTestHandler(t) diff --git a/hub/internal/api/handler.go b/hub/internal/api/handler.go index 7d59a90..35a436d 100644 --- a/hub/internal/api/handler.go +++ b/hub/internal/api/handler.go @@ -1423,17 +1423,21 @@ func (h *Handler) handleClaimResetRequest(w http.ResponseWriter, r *http.Request // allowedEventTypes lists all valid event_type values the Hub accepts. var allowedEventTypes = map[string]bool{ // Controller-pushed events - "controller_started": true, - "claim_lockout": true, // v0.50.0 — claim/reset code brute-force lockout tripped - "controller_updated": true, - "backup_completed": true, - "backup_failed": true, - "db_dump_completed": true, - "db_dump_failed": true, - "backup_integrity_ok": true, - "backup_integrity_failed": true, - "crossdrive_completed": true, - "crossdrive_failed": true, + "controller_started": true, + "claim_lockout": true, // v0.50.0 — claim/reset code brute-force lockout tripped + "controller_updated": true, + "backup_completed": true, + "backup_failed": true, + "db_dump_completed": true, + "db_dump_failed": true, + "backup_integrity_ok": true, + "backup_integrity_failed": true, + "crossdrive_completed": true, + "crossdrive_failed": true, + // controller v0.134.1 — enlarged offsite push refused by the quota gate (warning; the controller's + // dynamic Hungarian message is customer-grade — deliberately NO customerMessages entry, which would + // discard the numbers (templates.go:129 priority)). + "offbox_enlarge_blocked": true, "storage_disconnected": true, "storage_reconnected": true, "disk_warning": true, diff --git a/hub/internal/notify/templates_offbox_test.go b/hub/internal/notify/templates_offbox_test.go new file mode 100644 index 0000000..9c7b3bb --- /dev/null +++ b/hub/internal/notify/templates_offbox_test.go @@ -0,0 +1,31 @@ +package notify + +import ( + "strings" + "testing" +) + +// TestFormatCustomerEmail_OffboxEnlargeBlockedRawMessageSurvives locks in the deliberate non-change +// (Task 3a-fix): offbox_enlarge_blocked has NO customerMessages entry, so FormatCustomerEmail falls +// back to the controller's raw dynamic Hungarian message (templates.go:129) — the two-number text +// (estimate + quota) reaches the customer intact. A static customerMessages entry would DISCARD it. +func TestFormatCustomerEmail_OffboxEnlargeBlockedRawMessageSurvives(t *testing.T) { + // exactly the shape the controller sends (NotifyOffboxEnlargeBlocked). + raw := "A(z) immich teljes távoli mentése (~42.0 GB) túllépné a tárhelykeretet (20/50 GB). " + + "A konfiguráció és az adatbázis továbbra is mentésre kerül; nagyobb kerethez vedd fel velünk a kapcsolatot." + + // guard: the map must NOT gain an entry for this type (the trap). + if _, ok := customerMessages["offbox_enlarge_blocked"]; ok { + t.Fatal("offbox_enlarge_blocked must have NO customerMessages entry (it would discard the dynamic numbers)") + } + + subject, body := FormatCustomerEmail("c1", "offbox_enlarge_blocked", "warning", raw, "") + for _, want := range []string{"~42.0 GB", "20/50 GB"} { + if !strings.Contains(body, want) { + t.Errorf("email body must carry the dynamic figure %q (raw message survived): %s", want, body) + } + } + if !strings.Contains(subject, "túllépné a tárhelykeretet") { + t.Errorf("subject must carry the raw message, got %q", subject) + } +} diff --git a/manifests/hub.yaml b/manifests/hub.yaml index 4ee2f3a..b3aa714 100644 --- a/manifests/hub.yaml +++ b/manifests/hub.yaml @@ -125,7 +125,7 @@ spec: spec: containers: - name: hub - image: gitea.dooplex.hu/admin/felhom-hub:0.54.0 + image: gitea.dooplex.hu/admin/felhom-hub:0.55.0 ports: - containerPort: 8080 name: http