feat: interest over time graph (#127)

* api

* ui

* test

* add margin to prevent clipping
This commit is contained in:
Gabe Farrell 2026-01-12 16:20:31 -05:00 committed by GitHub
parent e45099c71a
commit 231eb1b0fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 1097 additions and 4 deletions

View file

@ -0,0 +1,47 @@
package handlers
import (
"net/http"
"strconv"
"github.com/gabehf/koito/internal/db"
"github.com/gabehf/koito/internal/logger"
"github.com/gabehf/koito/internal/utils"
)
func GetInterestHandler(store db.DB) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
l := logger.FromContext(ctx)
l.Debug().Msg("GetInterestHandler: Received request to retrieve interest")
// im just using this to parse the artist/album/track id, which is bad
parsed := OptsFromRequest(r)
bucketCountStr := r.URL.Query().Get("buckets")
var buckets = 0
var err error
if buckets, err = strconv.Atoi(bucketCountStr); err != nil {
l.Debug().Msg("GetInterestHandler: Buckets is not an integer")
utils.WriteError(w, "parameter 'buckets' must be an integer", http.StatusBadRequest)
return
}
opts := db.GetInterestOpts{
Buckets: buckets,
AlbumID: int32(parsed.AlbumID),
ArtistID: int32(parsed.ArtistID),
TrackID: int32(parsed.TrackID),
}
interest, err := store.GetInterest(ctx, opts)
if err != nil {
l.Err(err).Msg("GetInterestHandler: Failed to query interest")
utils.WriteError(w, "Failed to retrieve interest: "+err.Error(), http.StatusInternalServerError)
return
}
utils.WriteJSON(w, http.StatusOK, interest)
}
}

View file

@ -55,6 +55,7 @@ func bindRoutes(
r.Get("/search", handlers.SearchHandler(db))
r.Get("/aliases", handlers.GetAliasesHandler(db))
r.Get("/summary", handlers.SummaryHandler(db))
r.Get("/interest", handlers.GetInterestHandler(db))
})
r.Post("/logout", handlers.LogoutHandler(db))
if !cfg.RateLimitDisabled() {