feat(web): add status endpoint for archive, finish, and restore

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 13:00:21 +07:00
parent 5aae678668
commit 8579f5a0ed
2 changed files with 103 additions and 0 deletions
+27
View File
@@ -79,6 +79,7 @@ func (h *webHandler) register(mux *http.ServeMux) {
mux.HandleFunc("GET /ui/list", h.requireSession(h.uiList))
mux.HandleFunc("POST /ui/bookmarks/{key}/favorite", h.requireSession(h.uiFavorite))
mux.HandleFunc("POST /ui/bookmarks/{key}/status", h.requireSession(h.uiStatus))
mux.HandleFunc("POST /ui/bookmarks/{key}/chapter", h.requireSession(h.uiChapter))
mux.HandleFunc("DELETE /ui/bookmarks/{key}", h.requireSession(h.uiDelete))
}
@@ -283,6 +284,32 @@ func (h *webHandler) uiFavorite(w http.ResponseWriter, r *http.Request) {
h.saveAndRenderCard(w, b)
}
// uiStatus moves a bookmark between lifecycle buckets. This is the only place
// a series can be marked finished — the JSON API refuses that value, so the
// userscript cannot set it even by accident.
//
// last_chapter_num is untouched, so Upsert keeps the stored updated_at and the
// list does not reorder.
func (h *webHandler) uiStatus(w http.ResponseWriter, r *http.Request) {
b, ok := h.loadForMutation(w, r)
if !ok {
return
}
if err := r.ParseForm(); err != nil {
http.Error(w, "invalid form", http.StatusBadRequest)
return
}
switch s := r.PostFormValue("status"); s {
case statusReading, statusArchived, statusFinished:
b.Status = s
default:
http.Error(w, "invalid status", http.StatusBadRequest)
return
}
b.UpdatedAt = time.Now().UnixMilli()
h.saveAndRenderCard(w, b)
}
// uiChapter forces the read chapter to a value the user typed.
//
// Writing the number also clears last_chapter_url: that URL points at the