Dashboard writes were silently GETs

Publishing a notice did nothing and said it had worked. `api()` took only
`path` and dropped the options object every caller passes, so
`api(path, {method: "POST", body: ...})` fetched the URL. The read
succeeded -- notices are publicly listable -- so the page printed
"zveřejněno" over a collection that had not changed. Switching a notice
on or off is a PATCH and went the same way.

It takes method and body now, and reports what PocketBase said rather
than a bare status, so a permissions problem cannot look like an outage.

Found because the owner tried to tell the family that the anime tab is
down -- AniList have disabled their API, and every call returns 403 with
"The AniList API has been temporarily disabled due to severe stability
issues" -- and the notice never reached anyone.
This commit is contained in:
Claude 2026-09-02 21:50:21 +02:00
parent 271c423918
commit 5a4112f41f

View file

@ -206,10 +206,33 @@ function statusPill(s){
return '<span class="pill no">' + esc(t) + "</span>";
}
async function api(path){
var r = await fetch(path, { headers: { Authorization: tok } });
// Takes the options its callers have always passed.
//
// It used to accept only `path`, so every write on this page -- publishing a
// notice, switching one off -- was quietly performed as a GET. The read
// succeeded (the collection is publicly listable), so the page reported
// "zveřejněno" and nothing had been written. A notice about the anime tab being
// down never reached anyone.
async function api(path, opts){
opts = opts || {};
var init = { method: opts.method || "GET", headers: { Authorization: tok } };
if (opts.body !== undefined) {
init.headers["Content-Type"] = "application/json";
init.body = JSON.stringify(opts.body);
}
var r = await fetch(path, init);
if (r.status === 401) { logout(); throw new Error("401"); }
if (!r.ok) throw new Error("HTTP " + r.status);
if (!r.ok) {
// PocketBase explains itself in the body; say what it said rather than a
// bare status, or a permission problem looks the same as an outage.
var detail = "";
try {
var j = await r.json();
if (j && j.message) detail = ": " + j.message;
} catch (_) {}
throw new Error("HTTP " + r.status + detail);
}
if (r.status === 204) return null;
return r.json();
}