From 3e5a51c2722a117ea9ea164a73053bff991d3529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferdinand=20M=C3=BCtsch?= Date: Sun, 31 Jan 2021 16:23:47 +0100 Subject: [PATCH] feat: add missing query params to wakatime endpoints (resolve #109) --- models/compat/shields/v1/badge.go | 2 +- models/filters.go | 24 +------------------- models/summary.go | 21 +++++++++++++---- routes/compat/wakatime/v1/summaries.go | 31 ++++++++++++++++---------- utils/summary.go | 24 +++++++++++++++----- version.txt | 2 +- 6 files changed, 57 insertions(+), 47 deletions(-) diff --git a/models/compat/shields/v1/badge.go b/models/compat/shields/v1/badge.go index 515a2c8..27fc438 100644 --- a/models/compat/shields/v1/badge.go +++ b/models/compat/shields/v1/badge.go @@ -22,7 +22,7 @@ type BadgeData struct { func NewBadgeDataFrom(summary *models.Summary, filters *models.Filters) *BadgeData { var total time.Duration - if hasFilter, _, _ := filters.First(); hasFilter { + if hasFilter, _, _ := filters.One(); hasFilter { total = summary.TotalTimeByFilters(filters) } else { total = summary.TotalTime() diff --git a/models/filters.go b/models/filters.go index d660553..231c801 100644 --- a/models/filters.go +++ b/models/filters.go @@ -29,7 +29,7 @@ func NewFiltersWith(entity uint8, key string) *Filters { return &Filters{} } -func (f *Filters) First() (bool, uint8, string) { +func (f *Filters) One() (bool, uint8, string) { if f.Project != "" { return true, SummaryProject, f.Project } else if f.OS != "" { @@ -43,25 +43,3 @@ func (f *Filters) First() (bool, uint8, string) { } return false, 0, "" } - -func (f *Filters) All() []*FilterElement { - all := make([]*FilterElement, 0) - - if f.Project != "" { - all = append(all, &FilterElement{Type: SummaryProject, Key: f.Project}) - } - if f.Editor != "" { - all = append(all, &FilterElement{Type: SummaryEditor, Key: f.Editor}) - } - if f.Language != "" { - all = append(all, &FilterElement{Type: SummaryLanguage, Key: f.Language}) - } - if f.Machine != "" { - all = append(all, &FilterElement{Type: SummaryMachine, Key: f.Machine}) - } - if f.OS != "" { - all = append(all, &FilterElement{Type: SummaryOS, Key: f.OS}) - } - - return all -} diff --git a/models/summary.go b/models/summary.go index d808c6a..ea7ca43 100644 --- a/models/summary.go +++ b/models/summary.go @@ -24,6 +24,18 @@ const ( IntervalPast30Days string = "30_days" IntervalPast12Months string = "12_months" IntervalAny string = "any" + + // https://wakatime.com/developers/#summaries + IntervalWakatimeToday string = "Today" + IntervalWakatimeYesterday string = "Yesterday" + IntervalWakatimeLast7Days string = "Last 7 Days" + IntervalWakatimeLast7DaysYesterday string = "Last 7 Days from Yesterday" + IntervalWakatimeLast14Days string = "Last 14 Days" + IntervalWakatimeLast30Days string = "Last 30 Days" + IntervalWakatimeThisWeek string = "This Week" + IntervalWakatimeLastWeek string = "Last Week" + IntervalWakatimeThisMonth string = "This Month" + IntervalWakatimeLastMonth string = "Last Month" ) func Intervals() []string { @@ -188,11 +200,12 @@ func (s *Summary) TotalTimeByKey(entityType uint8, key string) (timeSum time.Dur return timeSum } -func (s *Summary) TotalTimeByFilters(filter *Filters) (timeSum time.Duration) { - for _, f := range filter.All() { - timeSum += s.TotalTimeByKey(f.Type, f.Key) +func (s *Summary) TotalTimeByFilters(filters *Filters) (timeSum time.Duration) { + do, typeId, key := filters.One() + if do { + return s.TotalTimeByKey(typeId, key) } - return timeSum + return s.TotalTime() } func (s *Summary) WithResolvedAliases(resolve AliasResolver) *Summary { diff --git a/routes/compat/wakatime/v1/summaries.go b/routes/compat/wakatime/v1/summaries.go index bae8cd1..62102e8 100644 --- a/routes/compat/wakatime/v1/summaries.go +++ b/routes/compat/wakatime/v1/summaries.go @@ -31,11 +31,10 @@ func (h *SummariesHandler) RegisterAPIRoutes(router *mux.Router) { router.Path("/summaries").Methods(http.MethodGet).HandlerFunc(h.ApiGet) } -/* -TODO: support parameters: project, branches, timeout, writes_only, timezone -https://wakatime.com/developers#summaries -timezone can be specified via an offset suffix (e.g. +02:00) in date strings -*/ +// TODO: Support parameters: project, branches, timeout, writes_only, timezone +// See https://wakatime.com/developers#summaries. +// Timezone can be specified via an offset suffix (e.g. +02:00) in date strings. +// Requires https://github.com/muety/wakapi/issues/108. func (h *SummariesHandler) ApiGet(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -54,28 +53,36 @@ func (h *SummariesHandler) ApiGet(w http.ResponseWriter, r *http.Request) { return } - vm := v1.NewSummariesFrom(summaries, &models.Filters{}) + filters := &models.Filters{} + if projectQuery := r.URL.Query().Get("project"); projectQuery != "" { + filters.Project = projectQuery + } + + vm := v1.NewSummariesFrom(summaries, filters) utils.RespondJSON(w, http.StatusOK, vm) } func (h *SummariesHandler) loadUserSummaries(r *http.Request) ([]*models.Summary, error, int) { user := r.Context().Value(models.UserKey).(*models.User) params := r.URL.Query() + rangeParam, startParam, endParam := params.Get("range"), params.Get("start"), params.Get("end") var start, end time.Time - // TODO: find out what other special dates are supported by wakatime (e.g. tomorrow, yesterday, ...?) - if startKey, endKey := params.Get("start"), params.Get("end"); startKey == "today" && startKey == endKey { - start = utils.StartOfToday() - end = time.Now() + if rangeParam != "" { + if err, parsedFrom, parsedTo := utils.ResolveInterval(rangeParam); err == nil { + start, end = parsedFrom, parsedTo + } else { + return nil, errors.New("invalid 'range' parameter"), http.StatusBadRequest + } } else { var err error - start, err = time.Parse(time.RFC3339, strings.Replace(startKey, " ", "+", 1)) + start, err = time.Parse(time.RFC3339, strings.Replace(startParam, " ", "+", 1)) if err != nil { return nil, errors.New("missing required 'start' parameter"), http.StatusBadRequest } - end, err = time.Parse(time.RFC3339, strings.Replace(endKey, " ", "+", 1)) + end, err = time.Parse(time.RFC3339, strings.Replace(endParam, " ", "+", 1)) if err != nil { return nil, errors.New("missing required 'end' parameter"), http.StatusBadRequest } diff --git a/utils/summary.go b/utils/summary.go index eaa1d13..1b31ed8 100644 --- a/utils/summary.go +++ b/utils/summary.go @@ -11,21 +11,33 @@ func ResolveInterval(interval string) (err error, from, to time.Time) { to = time.Now() switch interval { - case models.IntervalToday: + case models.IntervalToday, models.IntervalWakatimeToday: from = StartOfToday() - case models.IntervalYesterday: + case models.IntervalYesterday, models.IntervalWakatimeYesterday: from = StartOfToday().Add(-24 * time.Hour) to = StartOfToday() - case models.IntervalThisWeek: + case models.IntervalThisWeek, models.IntervalWakatimeThisWeek: from = StartOfWeek() - case models.IntervalThisMonth: + case models.IntervalWakatimeLastWeek: + from = StartOfWeek().AddDate(0, 0, -7) + to = StartOfWeek() + case models.IntervalThisMonth, models.IntervalWakatimeThisMonth: from = StartOfMonth() + case models.IntervalWakatimeLastMonth: + from = StartOfMonth().AddDate(0, -1, 0) + to = StartOfMonth() case models.IntervalThisYear: from = StartOfYear() - case models.IntervalPast7Days: + case models.IntervalPast7Days, models.IntervalWakatimeLast7Days: from = StartOfToday().AddDate(0, 0, -7) - case models.IntervalPast30Days: + case models.IntervalWakatimeLast7DaysYesterday: + from = StartOfToday().AddDate(0, 0, -1).AddDate(0, 0, -7) + to = StartOfToday().AddDate(0, 0, -1) + case models.IntervalWakatimeLast14Days: + from = StartOfToday().AddDate(0, 0, -14) + case models.IntervalPast30Days, models.IntervalWakatimeLast30Days: from = StartOfToday().AddDate(0, 0, -30) + from = StartOfToday().AddDate(0, -6, 0) case models.IntervalPast12Months: from = StartOfToday().AddDate(0, -12, 0) case models.IntervalAny: diff --git a/version.txt b/version.txt index 3cb1511..e4264e9 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.20.3 \ No newline at end of file +1.21.0 \ No newline at end of file