package api import ( "encoding/json" "net/http" "git.fabledsword.com/bvandeusen/minstrel/internal/apierror" "git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq" ) // handleGetMyHistory implements GET /api/me/history?limit=&offset=. // Returns the authenticated user's listening history (newest first), // excluding skipped events and quarantined tracks. Pagination is // offset/limit; has_more = (len(rows) == limit) is a cheap heuristic // that errs on the "true" side at the exact-end boundary. func (h *handlers) handleGetMyHistory(w http.ResponseWriter, r *http.Request) { user, ok := requireUser(w, r) if !ok { return } limit, offset, perr := parsePaging(r.URL.Query()) if perr != nil { writeErr(w, apierror.BadRequest("bad_paging", "invalid limit or offset")) return } rows, err := dbq.New(h.pool).ListUserHistory(r.Context(), dbq.ListUserHistoryParams{ UserID: user.ID, Limit: int32(limit), Offset: int32(offset), }) if err != nil { h.logger.Error("api: list user history", "err", err) writeErr(w, apierror.InternalMsg("failed to load history", err)) return } events := make([]HistoryEvent, 0, len(rows)) for _, row := range rows { events = append(events, HistoryEvent{ ID: uuidToString(row.EventID), PlayedAt: row.StartedAt.Time, Track: trackRefFrom(row.Track, row.AlbumTitle, row.ArtistName), }) } resp := HistoryResponse{ Events: events, HasMore: len(rows) == limit, } w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(resp) }