// package handlers implements route handlers package handlers import ( "net/http" "strconv" "strings" "time" "github.com/gabehf/koito/internal/db" "github.com/gabehf/koito/internal/logger" ) const defaultLimitSize = 100 const maximumLimit = 500 func OptsFromRequest(r *http.Request) db.GetItemsOpts { l := logger.FromContext(r.Context()) l.Debug().Msg("OptsFromRequest: Parsing query parameters") limitStr := r.URL.Query().Get("limit") limit, err := strconv.Atoi(limitStr) if err != nil { l.Debug().Msgf("OptsFromRequest: Query parameter 'limit' not specified, using default %d", defaultLimitSize) limit = defaultLimitSize } if limit > maximumLimit { l.Debug().Msgf("OptsFromRequest: Limit exceeds maximum %d, using default %d", maximumLimit, defaultLimitSize) limit = defaultLimitSize } pageStr := r.URL.Query().Get("page") page, _ := strconv.Atoi(pageStr) if page < 1 { l.Debug().Msg("OptsFromRequest: Page parameter is less than 1, defaulting to 1") page = 1 } artistIdStr := r.URL.Query().Get("artist_id") artistId, _ := strconv.Atoi(artistIdStr) albumIdStr := r.URL.Query().Get("album_id") albumId, _ := strconv.Atoi(albumIdStr) trackIdStr := r.URL.Query().Get("track_id") trackId, _ := strconv.Atoi(trackIdStr) tf := TimeframeFromRequest(r) var period db.Period switch strings.ToLower(r.URL.Query().Get("period")) { case "day": period = db.PeriodDay case "week": period = db.PeriodWeek case "month": period = db.PeriodMonth case "year": period = db.PeriodYear case "all_time": period = db.PeriodAllTime } l.Debug().Msgf("OptsFromRequest: Parsed options: limit=%d, page=%d, week=%d, month=%d, year=%d, from=%d, to=%d, artist_id=%d, album_id=%d, track_id=%d, period=%s", limit, page, tf.Week, tf.Month, tf.Year, tf.FromUnix, tf.ToUnix, artistId, albumId, trackId, period) return db.GetItemsOpts{ Limit: limit, Page: page, Timeframe: tf, ArtistID: artistId, AlbumID: albumId, TrackID: trackId, } } func TimeframeFromRequest(r *http.Request) db.Timeframe { q := r.URL.Query() parseInt := func(key string) int { v := q.Get(key) if v == "" { return 0 } i, _ := strconv.Atoi(v) return i } parseInt64 := func(key string) int64 { v := q.Get(key) if v == "" { return 0 } i, _ := strconv.ParseInt(v, 10, 64) return i } return db.Timeframe{ Period: db.Period(q.Get("period")), Year: parseInt("year"), Month: parseInt("month"), Week: parseInt("week"), FromUnix: parseInt64("from"), ToUnix: parseInt64("to"), Timezone: parseTZ(r), } } func parseTZ(r *http.Request) *time.Location { if tz := r.URL.Query().Get("tz"); tz != "" { if loc, err := time.LoadLocation(tz); err == nil { return loc } } if c, err := r.Cookie("tz"); err == nil { if loc, err := time.LoadLocation(c.Value); err == nil { return loc } } return time.Now().Location() }