1
0
mirror of https://github.com/muety/wakapi.git synced 2023-08-10 21:12:56 +03:00

feat: option to publicly share stats data (resolve #36)

This commit is contained in:
Ferdinand Mütsch
2021-02-06 22:32:03 +01:00
parent d1dc73b5e6
commit fca12f522f
12 changed files with 605 additions and 414 deletions

View File

@@ -10,6 +10,7 @@ import (
"net/http"
"regexp"
"strings"
"time"
)
const (
@@ -46,13 +47,6 @@ func (h *BadgeHandler) Get(w http.ResponseWriter, r *http.Request) {
return
}
requestedUserId := mux.Vars(r)["user"]
user, err := h.userSrvc.GetUserById(requestedUserId)
if err != nil || !user.BadgesEnabled {
w.WriteHeader(http.StatusUnauthorized)
return
}
var filterEntity, filterKey string
if groups := entityFilterReg.FindStringSubmatch(r.URL.Path); len(groups) > 2 {
filterEntity, filterKey = groups[1], groups[2]
@@ -65,6 +59,21 @@ func (h *BadgeHandler) Get(w http.ResponseWriter, r *http.Request) {
}
}
requestedUserId := mux.Vars(r)["user"]
user, err := h.userSrvc.GetUserById(requestedUserId)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
_, rangeFrom, rangeTo := utils.ResolveInterval(interval)
minStart := utils.StartOfDay(rangeTo.Add(-24 * time.Hour * time.Duration(user.ShareDataMaxDays)))
if rangeFrom.Before(minStart) {
w.WriteHeader(http.StatusForbidden)
w.Write([]byte("requested time range too broad"))
return
}
var filters *models.Filters
switch filterEntity {
case "project":

View File

@@ -1,7 +1,6 @@
package v1
import (
"errors"
"github.com/gorilla/mux"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
@@ -30,7 +29,7 @@ func NewStatsHandler(userService services.IUserService, summaryService services.
func (h *StatsHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/wakatime/v1/users/{user}/stats/{range}").Subrouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
middlewares.NewAuthenticateMiddleware(h.userSrvc).WithOptionalFor([]string{"/"}).Handler,
)
r.Methods(http.MethodGet).HandlerFunc(h.Get)
}
@@ -38,42 +37,69 @@ func (h *StatsHandler) RegisterRoutes(router *mux.Router) {
// TODO: support filtering (requires https://github.com/muety/wakapi/issues/108)
func (h *StatsHandler) Get(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
requestedUser := vars["user"]
requestedRange := vars["range"]
var vars = mux.Vars(r)
var authorizedUser, requestedUser *models.User
user := r.Context().Value(models.UserKey).(*models.User)
if u := r.Context().Value(models.UserKey); u != nil {
authorizedUser = u.(*models.User)
}
if requestedUser != user.ID && requestedUser != "current" {
w.WriteHeader(http.StatusForbidden)
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
}
summary, err, status := h.loadUserSummary(user, requestedRange)
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) &&
(requestedUser.ShareDataMaxDays == 0 || rangeFrom.Before(minStart)) {
w.WriteHeader(http.StatusForbidden)
w.Write([]byte("requested time range too broad"))
return
}
summary, err, status := h.loadUserSummary(requestedUser, rangeFrom, rangeTo)
if err != nil {
w.WriteHeader(status)
w.Write([]byte(err.Error()))
return
}
filters := &models.Filters{}
if projectQuery := r.URL.Query().Get("project"); projectQuery != "" {
filters.Project = projectQuery
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
}
vm := v1.NewStatsFrom(summary, filters)
utils.RespondJSON(w, http.StatusOK, vm)
utils.RespondJSON(w, http.StatusOK, stats)
}
func (h *StatsHandler) loadUserSummary(user *models.User, rangeKey string) (*models.Summary, error, int) {
var start, end time.Time
if err, parsedFrom, parsedTo := utils.ResolveIntervalRaw(rangeKey); err == nil {
start, end = parsedFrom, parsedTo
} else {
return nil, errors.New("invalid 'range' parameter"), http.StatusBadRequest
}
func (h *StatsHandler) loadUserSummary(user *models.User, start, end time.Time) (*models.Summary, error, int) {
overallParams := &models.SummaryParams{
From: start,
To: end,