From 1ab29b22e1a8a865ec0c4077915028e92eaf1744 Mon Sep 17 00:00:00 2001 From: Konstantin Kondr Date: Mon, 6 Sep 2021 17:01:49 +0000 Subject: [PATCH] add statusbar endpoint --- main.go | 2 + routes/compat/wakatime/v1/statusbar.go | 106 +++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 routes/compat/wakatime/v1/statusbar.go diff --git a/main.go b/main.go index f202d75..d8166cb 100644 --- a/main.go +++ b/main.go @@ -176,6 +176,7 @@ func main() { diagnosticsHandler := api.NewDiagnosticsApiHandler(userService, diagnosticsService) // Compat Handlers + wakatimeV1StatusBarHandler := wtV1Routes.NewStatusBarHandler(userService, summaryService) wakatimeV1AllHandler := wtV1Routes.NewAllTimeHandler(userService, summaryService) wakatimeV1SummariesHandler := wtV1Routes.NewSummariesHandler(userService, summaryService) wakatimeV1StatsHandler := wtV1Routes.NewStatsHandler(userService, summaryService) @@ -225,6 +226,7 @@ func main() { heartbeatApiHandler.RegisterRoutes(apiRouter) metricsHandler.RegisterRoutes(apiRouter) diagnosticsHandler.RegisterRoutes(apiRouter) + wakatimeV1StatusBarHandler.RegisterRoutes(apiRouter) wakatimeV1AllHandler.RegisterRoutes(apiRouter) wakatimeV1SummariesHandler.RegisterRoutes(apiRouter) wakatimeV1StatsHandler.RegisterRoutes(apiRouter) diff --git a/routes/compat/wakatime/v1/statusbar.go b/routes/compat/wakatime/v1/statusbar.go new file mode 100644 index 0000000..b779c84 --- /dev/null +++ b/routes/compat/wakatime/v1/statusbar.go @@ -0,0 +1,106 @@ +package v1 + +import ( + "net/http" + "time" + + "github.com/gorilla/mux" + conf "github.com/muety/wakapi/config" + "github.com/muety/wakapi/middlewares" + "github.com/muety/wakapi/models" + v1 "github.com/muety/wakapi/models/compat/wakatime/v1" + routeutils "github.com/muety/wakapi/routes/utils" + "github.com/muety/wakapi/services" + "github.com/muety/wakapi/utils" +) + +type StatusBarViewModel struct { + CachedAt time.Time `json:"cached_at"` + Data v1.SummariesData `json:"data"` +} + +type StatusBarHandler struct { + config *conf.Config + userSrvc services.IUserService + summarySrvc services.ISummaryService +} + +func NewStatusBarHandler(userService services.IUserService, summaryService services.ISummaryService) *StatusBarHandler { + return &StatusBarHandler{ + userSrvc: userService, + summarySrvc: summaryService, + config: conf.Get(), + } +} + +func (h *StatusBarHandler) RegisterRoutes(router *mux.Router) { + r := router.PathPrefix("").Subrouter() + + r.Use( + middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler, + ) + r.Path("/users/{user}/statusbar/{range}").Methods(http.MethodGet).HandlerFunc(h.Get) + r.Path("/v1/users/{user}/statusbar/{range}").Methods(http.MethodGet).HandlerFunc(h.Get) +} + +// @Summary Retrieve summary for statusbar +// @Description Mimics https://wakatime.com/api/v1/users/current/statusbar/today. Have no official documentation +// @ID statusbar +// @Tags wakatime +// @Produce json +// @Param user path string true "User ID to fetch data for (or 'current')" +// @Security ApiKeyAuth +// @Success 200 {object} v1.StatusBarViewModel +// @Router /users/{user}/statusbar/today [get] +func (h *StatusBarHandler) Get(w http.ResponseWriter, r *http.Request) { + user, err := routeutils.CheckEffectiveUser(w, r, h.userSrvc, "current") + if err != nil { + return // response was already sent by util function + } + var vars = mux.Vars(r) + + rangeParam := vars["range"] + if rangeParam == "" { + rangeParam = (*models.IntervalPast7Days)[0] + } + + err, rangeFrom, rangeTo := utils.ResolveIntervalRawTZ(rangeParam, user.TZ()) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte("invalid range")) + return + } + + summary, status, err := h.loadUserSummary(user, rangeFrom, rangeTo) + if err != nil { + w.WriteHeader(status) + w.Write([]byte(err.Error())) + return + } + summariesView := v1.NewSummariesFrom([]*models.Summary{summary}, &models.Filters{}) + utils.RespondJSON(w, r, http.StatusOK, StatusBarViewModel{ + CachedAt: time.Now(), + Data: *summariesView.Data[0], + }) +} + +func (h *StatusBarHandler) loadUserSummary(user *models.User, start, end time.Time) (*models.Summary, int, error) { + summaryParams := &models.SummaryParams{ + From: time.Time{}, + To: time.Now(), + User: user, + Recompute: false, + } + + var retrieveSummary services.SummaryRetriever = h.summarySrvc.Retrieve + if summaryParams.Recompute { + retrieveSummary = h.summarySrvc.Summarize + } + + summary, err := h.summarySrvc.Aliased(summaryParams.From, summaryParams.To, summaryParams.User, retrieveSummary, summaryParams.Recompute) + if err != nil { + return nil, http.StatusInternalServerError, err + } + + return summary, http.StatusOK, nil +}