diff --git a/internal/core/endpoints_repeater_test.go b/internal/core/endpoints_repeater_test.go index 28d0ee3..0def8ad 100644 --- a/internal/core/endpoints_repeater_test.go +++ b/internal/core/endpoints_repeater_test.go @@ -149,6 +149,54 @@ func TestRepeaterCrudPosts(t *testing.T) { assertRedirect(t, delRep, "/", "delete repeater") } +// TestAddRepeaterExposePublicPage: the add form's "Publish a public page" +// checkbox is honored at creation (not only on the edit page). Present → the +// repeater publishes a public page; absent → it does not. +func TestAddRepeaterExposePublicPage(t *testing.T) { + t.Parallel() + st, ctx, ts, h := splitServer(t) + _, sess := appLogin(t, ts, st, ctx, h.app, "exposer") + + exposed := func(t *testing.T, values url.Values) bool { + t.Helper() + resp := post(t, ts, h.app, "/repeaters", values, sess) + resp.Body.Close() + loc, _ := url.Parse(resp.Header.Get("Location")) + parts := strings.Split(loc.Path, "/") + if resp.StatusCode != http.StatusSeeOther || len(parts) < 3 { + t.Fatalf("create repeater = %d %q, want 303 → /repeaters/{id}/added", resp.StatusCode, resp.Header.Get("Location")) + } + var got bool + if err := st.Pool().QueryRow(ctx, + `SELECT expose_public_page FROM repeaters WHERE public_id = $1`, parts[2]).Scan(&got); err != nil { + t.Fatalf("read expose_public_page: %v", err) + } + return got + } + + radio := func(v url.Values) url.Values { + v.Set("radio_freq_mhz", "869.525") + v.Set("radio_bw_khz", "250") + v.Set("radio_sf", "11") + v.Set("radio_cr", "5") + return v + } + + onID, _ := meshcore.GenerateLocalIdentity(rand.Reader) + if !exposed(t, radio(url.Values{ + "name": {"Public Rep"}, "public_key": {onID.String()}, "expose_public_page": {"1"}, + })) { + t.Error("expose_public_page=1 at add time did not publish a public page") + } + + offID, _ := meshcore.GenerateLocalIdentity(rand.Reader) + if exposed(t, radio(url.Values{ + "name": {"Private Rep"}, "public_key": {offID.String()}, + })) { + t.Error("repeater added without the checkbox should not publish a public page") + } +} + // #81 create link, #82 delete link, #85 share commands, #86 steward, #83 unshare, // #87 org participation. func TestRepeaterSharePosts(t *testing.T) { diff --git a/internal/core/repeater_setup.go b/internal/core/repeater_setup.go index ed74003..392bb96 100644 --- a/internal/core/repeater_setup.go +++ b/internal/core/repeater_setup.go @@ -250,14 +250,15 @@ func (s *Handlers) handleSetupComplete(w http.ResponseWriter, r *http.Request) { } rep, err := s.Store.CreateRepeater(r.Context(), &store.Repeater{ - OwnerID: uid, - Name: name, - PublicKeyHex: pubHex, - RadioFreqHz: freq, - RadioBwHz: bw, - RadioSF: int16(sf), - RadioCR: int16(cr), - ShowOnPublicOrg: r.FormValue("show_on_public_org") != "", + OwnerID: uid, + Name: name, + PublicKeyHex: pubHex, + RadioFreqHz: freq, + RadioBwHz: bw, + RadioSF: int16(sf), + RadioCR: int16(cr), + ShowOnPublicOrg: r.FormValue("show_on_public_org") != "", + ExposePublicPage: r.FormValue("expose_public_page") != "", }) if errors.Is(err, store.ErrDuplicate) { http.Error(w, "you already added a repeater with that public key", http.StatusConflict) diff --git a/internal/core/repeater_setup_test.go b/internal/core/repeater_setup_test.go index 007d632..e53698c 100644 --- a/internal/core/repeater_setup_test.go +++ b/internal/core/repeater_setup_test.go @@ -131,7 +131,7 @@ func TestSerialSetupFlow(t *testing.T) { complete := url.Values{ "name": {"Hilltop"}, "public_key": {pub}, "radio_freq_mhz": {"910.525"}, "radio_bw_khz": {"62.5"}, "radio_sf": {"7"}, "radio_cr": {"5"}, - "lat": {"15.0"}, "lon": {"35.0"}, + "lat": {"15.0"}, "lon": {"35.0"}, "expose_public_page": {"1"}, } cResp := post(t, ts, h.app, "/repeaters/setup/complete", complete, sess) if cResp.StatusCode != http.StatusOK { @@ -160,6 +160,9 @@ func TestSerialSetupFlow(t *testing.T) { if got.Latitude == nil || got.Longitude == nil || *got.Latitude != 15.0 || *got.Longitude != 35.0 { t.Errorf("location not stored: %v, %v", got.Latitude, got.Longitude) } + if !got.ExposePublicPage { + t.Error("expose_public_page from the setup form was not persisted") + } } // TestBuildSetupCommands locks the from-scratch command order (header → profile diff --git a/internal/core/repeaters.go b/internal/core/repeaters.go index 52d8df2..64b19fd 100644 --- a/internal/core/repeaters.go +++ b/internal/core/repeaters.go @@ -201,14 +201,15 @@ func (s *Handlers) handleAddRepeater(w http.ResponseWriter, r *http.Request) { } rep, err := s.Store.CreateRepeater(r.Context(), &store.Repeater{ - OwnerID: uid, - Name: name, - PublicKeyHex: pubHex, - RadioFreqHz: freq, - RadioBwHz: bw, - RadioSF: int16(sf), - RadioCR: int16(cr), - ShowOnPublicOrg: r.FormValue("show_on_public_org") != "", + OwnerID: uid, + Name: name, + PublicKeyHex: pubHex, + RadioFreqHz: freq, + RadioBwHz: bw, + RadioSF: int16(sf), + RadioCR: int16(cr), + ShowOnPublicOrg: r.FormValue("show_on_public_org") != "", + ExposePublicPage: r.FormValue("expose_public_page") != "", }) if errors.Is(err, store.ErrDuplicate) { addErr(w, r, "You already added a repeater with that public key.") diff --git a/internal/core/templates/add_repeater.html b/internal/core/templates/add_repeater.html index c2d4482..a0ad1dc 100644 --- a/internal/core/templates/add_repeater.html +++ b/internal/core/templates/add_repeater.html @@ -237,6 +237,10 @@ Show this repeater on your organizations' public map. +