2021-02-06 18:05:34 +03:00
|
|
|
package v1
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
conf "github.com/muety/wakapi/config"
|
2021-02-06 22:09:08 +03:00
|
|
|
"github.com/muety/wakapi/middlewares"
|
2021-02-06 18:05:34 +03:00
|
|
|
"github.com/muety/wakapi/models"
|
|
|
|
v1 "github.com/muety/wakapi/models/compat/wakatime/v1"
|
|
|
|
"github.com/muety/wakapi/services"
|
|
|
|
"github.com/muety/wakapi/utils"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type StatsHandler struct {
|
|
|
|
config *conf.Config
|
2021-02-06 22:09:08 +03:00
|
|
|
userSrvc services.IUserService
|
2021-02-06 18:05:34 +03:00
|
|
|
summarySrvc services.ISummaryService
|
|
|
|
}
|
|
|
|
|
2021-02-06 22:09:08 +03:00
|
|
|
func NewStatsHandler(userService services.IUserService, summaryService services.ISummaryService) *StatsHandler {
|
2021-02-06 18:05:34 +03:00
|
|
|
return &StatsHandler{
|
2021-02-06 22:09:08 +03:00
|
|
|
userSrvc: userService,
|
2021-02-06 18:05:34 +03:00
|
|
|
summarySrvc: summaryService,
|
|
|
|
config: conf.Get(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *StatsHandler) RegisterRoutes(router *mux.Router) {
|
2021-02-07 00:40:54 +03:00
|
|
|
r := router.PathPrefix("").Subrouter()
|
2021-02-06 22:09:08 +03:00
|
|
|
r.Use(
|
2021-02-07 00:32:03 +03:00
|
|
|
middlewares.NewAuthenticateMiddleware(h.userSrvc).WithOptionalFor([]string{"/"}).Handler,
|
2021-02-06 22:09:08 +03:00
|
|
|
)
|
2021-02-07 00:40:54 +03:00
|
|
|
r.Path("/v1/users/{user}/stats/{range}").Methods(http.MethodGet).HandlerFunc(h.Get)
|
|
|
|
r.Path("/compat/wakatime/v1/users/{user}/stats/{range}").Methods(http.MethodGet).HandlerFunc(h.Get)
|
2021-02-06 18:05:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: support filtering (requires https://github.com/muety/wakapi/issues/108)
|
|
|
|
|
|
|
|
func (h *StatsHandler) Get(w http.ResponseWriter, r *http.Request) {
|
2021-02-07 00:32:03 +03:00
|
|
|
var vars = mux.Vars(r)
|
|
|
|
var authorizedUser, requestedUser *models.User
|
2021-02-06 18:05:34 +03:00
|
|
|
|
2021-02-07 00:32:03 +03:00
|
|
|
if u := r.Context().Value(models.UserKey); u != nil {
|
|
|
|
authorizedUser = u.(*models.User)
|
|
|
|
}
|
|
|
|
|
|
|
|
if authorizedUser != nil && vars["user"] == "current" {
|
|
|
|
vars["user"] = authorizedUser.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
requestedUser, err := h.userSrvc.GetUserById(vars["user"])
|
|
|
|
if err != nil {
|
|
|
|
w.WriteHeader(http.StatusNotFound)
|
|
|
|
w.Write([]byte("user not found"))
|
|
|
|
return
|
|
|
|
}
|
2021-02-06 18:05:34 +03:00
|
|
|
|
2021-02-07 00:32:03 +03:00
|
|
|
err, rangeFrom, rangeTo := utils.ResolveIntervalRaw(vars["range"])
|
|
|
|
if err != nil {
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
w.Write([]byte("invalid range"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
minStart := utils.StartOfDay(rangeTo.Add(-24 * time.Hour * time.Duration(requestedUser.ShareDataMaxDays)))
|
|
|
|
if (authorizedUser == nil || requestedUser.ID != authorizedUser.ID) &&
|
2021-02-07 01:23:26 +03:00
|
|
|
rangeFrom.Before(minStart) && requestedUser.ShareDataMaxDays >= 0 {
|
2021-02-06 18:05:34 +03:00
|
|
|
w.WriteHeader(http.StatusForbidden)
|
2021-02-07 00:32:03 +03:00
|
|
|
w.Write([]byte("requested time range too broad"))
|
2021-02-06 18:05:34 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-02-07 00:32:03 +03:00
|
|
|
summary, err, status := h.loadUserSummary(requestedUser, rangeFrom, rangeTo)
|
2021-02-06 18:05:34 +03:00
|
|
|
if err != nil {
|
|
|
|
w.WriteHeader(status)
|
|
|
|
w.Write([]byte(err.Error()))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-02-07 00:32:03 +03:00
|
|
|
stats := v1.NewStatsFrom(summary, &models.Filters{})
|
|
|
|
|
|
|
|
// post filter stats according to user's given sharing permissions
|
|
|
|
if !requestedUser.ShareEditors {
|
|
|
|
stats.Data.Editors = nil
|
|
|
|
}
|
|
|
|
if !requestedUser.ShareLanguages {
|
|
|
|
stats.Data.Languages = nil
|
|
|
|
}
|
|
|
|
if !requestedUser.ShareProjects {
|
|
|
|
stats.Data.Projects = nil
|
|
|
|
}
|
|
|
|
if !requestedUser.ShareOSs {
|
|
|
|
stats.Data.OperatingSystems = nil
|
|
|
|
}
|
|
|
|
if !requestedUser.ShareMachines {
|
|
|
|
stats.Data.Machines = nil
|
2021-02-06 18:05:34 +03:00
|
|
|
}
|
|
|
|
|
2021-02-07 00:32:03 +03:00
|
|
|
utils.RespondJSON(w, http.StatusOK, stats)
|
2021-02-06 18:05:34 +03:00
|
|
|
}
|
|
|
|
|
2021-02-07 00:32:03 +03:00
|
|
|
func (h *StatsHandler) loadUserSummary(user *models.User, start, end time.Time) (*models.Summary, error, int) {
|
2021-02-06 18:05:34 +03:00
|
|
|
overallParams := &models.SummaryParams{
|
|
|
|
From: start,
|
|
|
|
To: end,
|
|
|
|
User: user,
|
|
|
|
Recompute: false,
|
|
|
|
}
|
|
|
|
|
|
|
|
summary, err := h.summarySrvc.Aliased(overallParams.From, overallParams.To, user, h.summarySrvc.Retrieve)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err, http.StatusInternalServerError
|
|
|
|
}
|
|
|
|
|
|
|
|
return summary, nil, http.StatusOK
|
|
|
|
}
|