fix(podcasts): order selector validation — bind the htmx form wire format (issue #2)
WHY: htmx sends non-GET requests urlencoded by default; the SetFeedOrder request struct only carried a json tag, so the binder left Order empty and 'required' fired — the exact error the order dropdown AND the Serial-suggestion button produced (hx-vals JSON also arrives form-encoded). One form tag fixes both controls. Regression test drives the exact wire format: urlencoded PUT with order=oldest/native → 200, empty/invalid → 400.
This commit is contained in:
1 parent
8d9fb0046c
commit
c753780817
2 files changed
+35
-1
No files matched your search
@@ -19,6 +19,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -663,3 +664,36 @@ func adminScopeExec(t *testing.T, setup *TestServerSetup, adminID pgtype.UUID, s
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ---- task 1.9 residue: the htmx wire format is FORM-encoded (issue #2) ----
|
||||
|
||||
func TestPodcastOrderFormEncoding(t *testing.T) {
|
||||
setup := setupTestServer(t)
|
||||
lib, _ := createPodcastsLibrary(t, setup, "test OrderForm Podcasts")
|
||||
feed, err := setup.DB.CreatePodcastFeed(adminSeedCtx(t, setup), database.CreatePodcastFeedParams{
|
||||
LibraryID: lib.ID,
|
||||
FeedUrl: "https://feed.invalid/order-form.xml",
|
||||
Title: "Order Form Feed",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
feedIDStr := uuid.UUID(feed.ID.Bytes).String()
|
||||
|
||||
// The UI's hx-put submits urlencoded form bodies (htmx non-GET
|
||||
// default) — the binder must map them (form tag), not just JSON.
|
||||
formPut := func(body string) int {
|
||||
req, _ := http.NewRequest(http.MethodPut,
|
||||
setup.Server.URL+"/api/podcasts/feeds/"+feedIDStr+"/order",
|
||||
strings.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Set("Authorization", "Bearer "+setup.Token)
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
require.NoError(t, err)
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
return resp.StatusCode
|
||||
}
|
||||
|
||||
assert.Equal(t, http.StatusOK, formPut("order=oldest"), "form-encoded order must bind")
|
||||
assert.Equal(t, http.StatusOK, formPut("order=native"), "native binds too")
|
||||
assert.Equal(t, http.StatusBadRequest, formPut(""), "missing order stays rejected (required)")
|
||||
assert.Equal(t, http.StatusBadRequest, formPut("order=sideways"), "invalid order stays rejected")
|
||||
}
|
||||
@@ -459,7 +459,7 @@ func (h *PodcastHandler) SetFeedOrder(c *echo.Context) error {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid feed id"})
|
||||
}
|
||||
var req struct {
|
||||
Order string `json:"order" validate:"required,oneof=native oldest newest"`
|
||||
Order string `json:"order" form:"order" validate:"required,oneof=native oldest newest"`
|
||||
}
|
||||
if err := c.Bind(&req); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"})
|
||||
|
||||
Reference in new issue
Block a user