From fb7b45dbdf23ddcb9209b6beb973ead20c259b4b Mon Sep 17 00:00:00 2001 From: Jonathon Leight Date: Thu, 30 Jul 2026 22:17:52 -0400 Subject: [PATCH] Transfer repeater ownership --- internal/core/dbtest_test.go | 13 +- internal/core/repeaters.go | 3 +- internal/core/templates/add_repeater.html | 50 ++- internal/core/templates/delete_repeater.html | 23 +- internal/core/templates/edit_repeater.html | 2 +- internal/core/templates/repeater.html | 9 +- internal/core/templates/repeater_docs.html | 2 +- internal/core/templates/share.html | 19 +- .../core/templates/transfer_repeater.html | 127 ++++++++ internal/core/transfer.go | 89 +++++ internal/core/transfer_endpoint_test.go | 237 ++++++++++++++ internal/core/web.go | 2 + internal/e2e/harness_test.go | 17 + internal/e2e/password_reset_test.go | 15 - internal/e2e/transfer_test.go | 74 +++++ internal/marketing/marketing.go | 4 +- internal/marketing/repeaters.go | 2 +- internal/seed/seed.go | 2 +- internal/store/repeaters.go | 4 +- internal/store/transfer.go | 167 ++++++++++ internal/store/transfer_test.go | 305 ++++++++++++++++++ internal/web/robots.go | 2 +- 22 files changed, 1101 insertions(+), 67 deletions(-) create mode 100644 internal/core/templates/transfer_repeater.html create mode 100644 internal/core/transfer.go create mode 100644 internal/core/transfer_endpoint_test.go create mode 100644 internal/e2e/transfer_test.go create mode 100644 internal/store/transfer.go create mode 100644 internal/store/transfer_test.go diff --git a/internal/core/dbtest_test.go b/internal/core/dbtest_test.go index 0863b1b..c6f06b3 100644 --- a/internal/core/dbtest_test.go +++ b/internal/core/dbtest_test.go @@ -23,6 +23,15 @@ func appLogin(t *testing.T, ts *httptest.Server, st *store.Store, ctx context.Co if err != nil { t.Fatalf("create user: %v", err) } + return u, appSession(t, ts, st, ctx, host, u) +} + +// appSession signs an EXISTING user in, returning an app-host session cookie. It +// is appLogin without the account creation, for tests that need a session for +// someone another part of the fixture already created (a steward, a share +// recipient) — calling appLogin for them would fail on the duplicate username. +func appSession(t *testing.T, ts *httptest.Server, st *store.Store, ctx context.Context, host string, u *store.User) *http.Cookie { + t.Helper() loginID, err := st.CreateLogin(ctx, u.ID) if err != nil { t.Fatalf("create login: %v", err) @@ -35,9 +44,9 @@ func appLogin(t *testing.T, ts *httptest.Server, st *store.Store, ctx context.Co resp.Body.Close() c := cookieByName(resp, "meshtender_session") if c == nil { - t.Fatalf("no app session cookie after handoff for %q", username) + t.Fatalf("no app session cookie after handoff for %q", u.Username) } - return u, c + return c } // testConfig/testAuthConfig give the integration tests the app/auth/root hosts, diff --git a/internal/core/repeaters.go b/internal/core/repeaters.go index 64b19fd..2a175a9 100644 --- a/internal/core/repeaters.go +++ b/internal/core/repeaters.go @@ -104,9 +104,10 @@ func (s *Handlers) pageRepeater(w http.ResponseWriter, r *http.Request) { "Radio": radio, "ContactURI": contactURI, "Error": r.URL.Query().Get("error"), + "OK": r.URL.Query().Get("ok"), } // When the owner has published a public page, surface its link plus a QR code - // to print and place inside the enclosure (the NFC/QR tap target). + // for it. if isOwner && rep.ExposePublicPage { publicURL := s.Origin(r, s.rootHost()) + "/r/" + rep.PublicID data["PublicPageURL"] = publicURL diff --git a/internal/core/templates/add_repeater.html b/internal/core/templates/add_repeater.html index 070fca4..c905b3a 100644 --- a/internal/core/templates/add_repeater.html +++ b/internal/core/templates/add_repeater.html @@ -61,19 +61,17 @@