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

refactor: replace gorilla mux with chi

This commit is contained in:
Ferdinand Mütsch
2023-03-03 20:40:50 +01:00
parent e495468be2
commit a6ef735ba1
32 changed files with 1407 additions and 1582 deletions

View File

@@ -2,7 +2,7 @@ package api
import (
"codeberg.org/Codeberg/avatars"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
lru "github.com/hashicorp/golang-lru"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/utils"
@@ -27,13 +27,12 @@ func NewAvatarHandler() *AvatarHandler {
}
}
func (h *AvatarHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/avatar/{hash}.svg").Subrouter()
r.Path("").Methods(http.MethodGet).HandlerFunc(h.Get)
func (h *AvatarHandler) RegisterRoutes(router chi.Router) {
router.Get("/avatar/{hash}.svg", h.Get)
}
func (h *AvatarHandler) Get(w http.ResponseWriter, r *http.Request) {
hash := mux.Vars(r)["hash"]
hash := chi.URLParam(r, "hash")
if utils.IsNoCache(r, 1*time.Hour) {
h.cache.Remove(hash)

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"github.com/duke-git/lancet/v2/maputil"
"github.com/duke-git/lancet/v2/slice"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models"
v1 "github.com/muety/wakapi/models/compat/shields/v1"
@@ -33,13 +33,12 @@ func NewBadgeHandler(userService services.IUserService, summaryService services.
}
}
func (h *BadgeHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/badge/{user}").Subrouter()
r.Methods(http.MethodGet).HandlerFunc(h.Get)
func (h *BadgeHandler) RegisterRoutes(router chi.Router) {
router.Get("/badge/{user}", h.Get)
}
func (h *BadgeHandler) Get(w http.ResponseWriter, r *http.Request) {
user, err := h.userSrvc.GetUserById(mux.Vars(r)["user"])
user, err := h.userSrvc.GetUserById(chi.URLParam(r, "user"))
if err != nil {
w.WriteHeader(http.StatusNotFound)
return

View File

@@ -2,10 +2,10 @@ package api
import (
"encoding/json"
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/helpers"
"net/http"
"github.com/gorilla/mux"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/services"
@@ -25,9 +25,8 @@ func NewDiagnosticsApiHandler(userService services.IUserService, diagnosticsServ
}
}
func (h *DiagnosticsApiHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/plugins/errors").Subrouter()
r.Path("").Methods(http.MethodPost).HandlerFunc(h.Post)
func (h *DiagnosticsApiHandler) RegisterRoutes(router chi.Router) {
router.Post("/plugins/errors", h.Post)
}
// @Summary Push a new diagnostics object

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
"gorm.io/gorm"
)
@@ -16,9 +16,8 @@ func NewHealthApiHandler(db *gorm.DB) *HealthApiHandler {
return &HealthApiHandler{db: db}
}
func (h *HealthApiHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/health").Subrouter()
r.Path("").Methods(http.MethodGet).HandlerFunc(h.Get)
func (h *HealthApiHandler) RegisterRoutes(router chi.Router) {
router.Get("/health", h.Get)
}
// @Summary Check the application's health status

View File

@@ -1,10 +1,10 @@
package api
import (
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/helpers"
"net/http"
"github.com/gorilla/mux"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
customMiddleware "github.com/muety/wakapi/middlewares/custom"
@@ -35,21 +35,22 @@ type heartbeatResponseVm struct {
Responses [][]interface{} `json:"responses"`
}
func (h *HeartbeatApiHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("").Subrouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
customMiddleware.NewWakatimeRelayMiddleware().Handler,
)
// see https://github.com/muety/wakapi/issues/203
r.Path("/heartbeat").Methods(http.MethodPost).HandlerFunc(h.Post)
r.Path("/heartbeats").Methods(http.MethodPost).HandlerFunc(h.Post)
r.Path("/users/{user}/heartbeats").Methods(http.MethodPost).HandlerFunc(h.Post)
r.Path("/users/{user}/heartbeats.bulk").Methods(http.MethodPost).HandlerFunc(h.Post)
r.Path("/v1/users/{user}/heartbeats").Methods(http.MethodPost).HandlerFunc(h.Post)
r.Path("/v1/users/{user}/heartbeats.bulk").Methods(http.MethodPost).HandlerFunc(h.Post)
r.Path("/compat/wakatime/v1/users/{user}/heartbeats").Methods(http.MethodPost).HandlerFunc(h.Post)
r.Path("/compat/wakatime/v1/users/{user}/heartbeats.bulk").Methods(http.MethodPost).HandlerFunc(h.Post)
func (h *HeartbeatApiHandler) RegisterRoutes(router chi.Router) {
router.Group(func(r chi.Router) {
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
customMiddleware.NewWakatimeRelayMiddleware().Handler,
)
// see https://github.com/muety/wakapi/issues/203
r.Post("/heartbeat", h.Post)
r.Post("/heartbeats", h.Post)
r.Post("/users/{user}/heartbeats", h.Post)
r.Post("/users/{user}/heartbeats.bulk", h.Post)
r.Post("/v1/users/{user}/heartbeats", h.Post)
r.Post("/v1/users/{user}/heartbeats.bulk", h.Post)
r.Post("/compat/wakatime/v1/users/{user}/heartbeats", h.Post)
r.Post("/compat/wakatime/v1/users/{user}/heartbeats.bulk", h.Post)
})
}
// @Summary Push a new heartbeat

View File

@@ -3,7 +3,7 @@ package api
import (
"errors"
"github.com/emvi/logbuch"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/helpers"
"github.com/muety/wakapi/middlewares"
@@ -66,18 +66,18 @@ func NewMetricsHandler(userService services.IUserService, summaryService service
}
}
func (h *MetricsHandler) RegisterRoutes(router *mux.Router) {
func (h *MetricsHandler) RegisterRoutes(router chi.Router) {
if !h.config.Security.ExposeMetrics {
return
}
logbuch.Info("exposing prometheus metrics under /api/metrics")
r := router.PathPrefix("/metrics").Subrouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
)
r.Path("").Methods(http.MethodGet).HandlerFunc(h.Get)
r := chi.NewRouter()
r.Use(middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler)
r.Get("/", h.Get)
router.Mount("/metrics", r)
}
func (h *MetricsHandler) Get(w http.ResponseWriter, r *http.Request) {

View File

@@ -1,11 +1,11 @@
package api
import (
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/helpers"
routeutils "github.com/muety/wakapi/routes/utils"
"net/http"
"github.com/gorilla/mux"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/services"
@@ -25,12 +25,12 @@ func NewSummaryApiHandler(userService services.IUserService, summaryService serv
}
}
func (h *SummaryApiHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/summary").Subrouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
)
r.Path("").Methods(http.MethodGet).HandlerFunc(h.Get)
func (h *SummaryApiHandler) RegisterRoutes(router chi.Router) {
r := chi.NewRouter()
r.Use(middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler)
r.Get("/", h.Get)
router.Mount("/summary", r)
}
// @Summary Retrieve a summary

View File

@@ -2,12 +2,12 @@ package v1
import (
"fmt"
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/helpers"
routeutils "github.com/muety/wakapi/routes/utils"
"net/http"
"time"
"github.com/gorilla/mux"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models"
v1 "github.com/muety/wakapi/models/compat/shields/v1"
@@ -31,10 +31,9 @@ func NewBadgeHandler(summaryService services.ISummaryService, userService servic
}
}
func (h *BadgeHandler) RegisterRoutes(router *mux.Router) {
func (h *BadgeHandler) RegisterRoutes(router chi.Router) {
// no auth middleware here, handler itself resolves the user
r := router.PathPrefix("/compat/shields/v1/{user}").Subrouter()
r.Methods(http.MethodGet).HandlerFunc(h.Get)
router.Get("/compat/shields/v1/{user}/*", h.Get)
}
// @Summary Get badge data
@@ -48,7 +47,7 @@ func (h *BadgeHandler) RegisterRoutes(router *mux.Router) {
// @Success 200 {object} v1.BadgeData
// @Router /compat/shields/v1/{user}/{interval}/{filter} [get]
func (h *BadgeHandler) Get(w http.ResponseWriter, r *http.Request) {
user, err := h.userSrvc.GetUserById(mux.Vars(r)["user"])
user, err := h.userSrvc.GetUserById(chi.URLParam(r, "user"))
if err != nil {
w.WriteHeader(http.StatusNotFound)
return

View File

@@ -1,7 +1,7 @@
package v1
import (
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/helpers"
"github.com/muety/wakapi/middlewares"
@@ -27,12 +27,11 @@ func NewAllTimeHandler(userService services.IUserService, summaryService service
}
}
func (h *AllTimeHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/compat/wakatime/v1/users/{user}/all_time_since_today").Subrouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
)
r.Path("").Methods(http.MethodGet).HandlerFunc(h.Get)
func (h *AllTimeHandler) RegisterRoutes(router chi.Router) {
router.Group(func(r chi.Router) {
r.Use(middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler)
r.Get("/compat/wakatime/v1/users/{user}/all_time_since_today", h.Get)
})
}
// @Summary Retrieve summary for all time

View File

@@ -2,11 +2,11 @@ package v1
import (
"github.com/duke-git/lancet/v2/datetime"
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/helpers"
"net/http"
"time"
"github.com/gorilla/mux"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
wakatime "github.com/muety/wakapi/models/compat/wakatime/v1"
@@ -33,12 +33,11 @@ func NewHeartbeatHandler(userService services.IUserService, heartbeatService ser
}
}
func (h *HeartbeatHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("").Subrouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
)
r.Path("/compat/wakatime/v1/users/{user}/heartbeats").Methods(http.MethodGet).HandlerFunc(h.Get)
func (h *HeartbeatHandler) RegisterRoutes(router chi.Router) {
router.Group(func(r chi.Router) {
r.Use(middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler)
r.Get("/compat/wakatime/v1/users/{user}/heartbeats", h.Get)
})
}
// @Summary Get heartbeats of user for specified date

View File

@@ -1,11 +1,11 @@
package v1
import (
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/helpers"
"net/http"
"strings"
"github.com/gorilla/mux"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/models"
@@ -28,12 +28,11 @@ func NewProjectsHandler(userService services.IUserService, heartbeatsService ser
}
}
func (h *ProjectsHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/compat/wakatime/v1/users/{user}/projects").Subrouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
)
r.Path("").Methods(http.MethodGet).HandlerFunc(h.Get)
func (h *ProjectsHandler) RegisterRoutes(router chi.Router) {
router.Group(func(r chi.Router) {
r.Use(middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler)
r.Get("/compat/wakatime/v1/users/{user}/projects", h.Get)
})
}
// @Summary Retrieve and fitler the user's projects

View File

@@ -1,11 +1,11 @@
package v1
import (
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/helpers"
"net/http"
"time"
"github.com/gorilla/mux"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/models"
@@ -27,17 +27,18 @@ func NewStatsHandler(userService services.IUserService, summaryService services.
}
}
func (h *StatsHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("").Subrouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).WithOptionalFor([]string{"/"}).Handler,
)
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)
func (h *StatsHandler) RegisterRoutes(router chi.Router) {
router.Group(func(r chi.Router) {
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).WithOptionalFor([]string{"/"}).Handler,
)
r.Get("/v1/users/{user}/stats/{range}", h.Get)
r.Get("/compat/wakatime/v1/users/{user}/stats/{range}", h.Get)
// Also works without range, see https://github.com/anuraghazra/github-readme-stats/issues/865#issuecomment-776186592
r.Path("/v1/users/{user}/stats").Methods(http.MethodGet).HandlerFunc(h.Get)
r.Path("/compat/wakatime/v1/users/{user}/stats").Methods(http.MethodGet).HandlerFunc(h.Get)
// Also works without range, see https://github.com/anuraghazra/github-readme-stats/issues/865#issuecomment-776186592
r.Get("/v1/users/{user}/stats", h.Get)
r.Get("/compat/wakatime/v1/users/{user}/stats", h.Get)
})
}
// TODO: support filtering (requires https://github.com/muety/wakapi/issues/108)
@@ -59,22 +60,22 @@ func (h *StatsHandler) RegisterRoutes(router *mux.Router) {
// @Success 200 {object} v1.StatsViewModel
// @Router /compat/wakatime/v1/users/{user}/stats/{range} [get]
func (h *StatsHandler) Get(w http.ResponseWriter, r *http.Request) {
var vars = mux.Vars(r)
userParam := chi.URLParam(r, "user")
rangeParam := chi.URLParam(r, "range")
var authorizedUser, requestedUser *models.User
authorizedUser = middlewares.GetPrincipal(r)
if authorizedUser != nil && vars["user"] == "current" {
vars["user"] = authorizedUser.ID
if authorizedUser != nil && userParam == "current" {
userParam = authorizedUser.ID
}
requestedUser, err := h.userSrvc.GetUserById(vars["user"])
requestedUser, err := h.userSrvc.GetUserById(userParam)
if err != nil {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("user not found"))
return
}
rangeParam := vars["range"]
if rangeParam == "" {
rangeParam = (*models.IntervalPast7Days)[0]
}

View File

@@ -1,11 +1,11 @@
package v1
import (
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/helpers"
"net/http"
"time"
"github.com/gorilla/mux"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/models"
@@ -33,15 +33,13 @@ func NewStatusBarHandler(userService services.IUserService, summaryService servi
}
}
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)
r.Path("/compat/wakatime/v1/users/{user}/statusbar/{range}").Methods(http.MethodGet).HandlerFunc(h.Get)
func (h *StatusBarHandler) RegisterRoutes(router chi.Router) {
router.Group(func(r chi.Router) {
r.Use(middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler)
r.Get("/users/{user}/statusbar/{range}", h.Get)
r.Get("/v1/users/{user}/statusbar/{range}", h.Get)
r.Get("/compat/wakatime/v1/users/{user}/statusbar/{range}", h.Get)
})
}
// @Summary Retrieve summary for statusbar
@@ -58,9 +56,8 @@ func (h *StatusBarHandler) Get(w http.ResponseWriter, r *http.Request) {
if err != nil {
return // response was already sent by util function
}
var vars = mux.Vars(r)
rangeParam := vars["range"]
rangeParam := chi.URLParam(r, "range")
if rangeParam == "" {
rangeParam = (*models.IntervalToday)[0]
}

View File

@@ -3,12 +3,12 @@ package v1
import (
"errors"
"github.com/duke-git/lancet/v2/datetime"
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/helpers"
"net/http"
"strings"
"time"
"github.com/gorilla/mux"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/models"
@@ -32,12 +32,11 @@ func NewSummariesHandler(userService services.IUserService, summaryService servi
}
}
func (h *SummariesHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/compat/wakatime/v1/users/{user}/summaries").Subrouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
)
r.Path("").Methods(http.MethodGet).HandlerFunc(h.Get)
func (h *SummariesHandler) RegisterRoutes(router chi.Router) {
router.Group(func(r chi.Router) {
r.Use(middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler)
r.Get("/compat/wakatime/v1/users/{user}/summaries", h.Get)
})
}
// TODO: Support parameters: project, branches, timeout, writes_only

View File

@@ -0,0 +1,17 @@
package v1
import (
"context"
"github.com/go-chi/chi/v5"
"net/http"
"strings"
)
func withUrlParam(r *http.Request, key, value string) *http.Request {
r.URL.RawPath = strings.Replace(r.URL.RawPath, "{"+key+"}", value, 1)
r.URL.Path = strings.Replace(r.URL.Path, "{"+key+"}", value, 1)
rctx := chi.NewRouteContext()
rctx.URLParams.Add(key, value)
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
return r
}

View File

@@ -1,10 +1,10 @@
package v1
import (
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/helpers"
"net/http"
"github.com/gorilla/mux"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
v1 "github.com/muety/wakapi/models/compat/wakatime/v1"
@@ -26,12 +26,11 @@ func NewUsersHandler(userService services.IUserService, heartbeatService service
}
}
func (h *UsersHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/compat/wakatime/v1/users/{user}").Subrouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
)
r.Path("").Methods(http.MethodGet).HandlerFunc(h.Get)
func (h *UsersHandler) RegisterRoutes(router chi.Router) {
router.Group(func(r chi.Router) {
r.Use(middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler)
r.Get("/compat/wakatime/v1/users/{user}", h.Get)
})
}
// @Summary Retrieve the given user

View File

@@ -3,7 +3,7 @@ package v1
import (
"encoding/base64"
"fmt"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/mocks"
"github.com/muety/wakapi/models"
@@ -36,9 +36,10 @@ var (
)
func TestUsersHandler_Get(t *testing.T) {
router := mux.NewRouter()
apiRouter := router.PathPrefix("/api").Subrouter().StrictSlash(true)
router := chi.NewRouter()
apiRouter := chi.NewRouter()
apiRouter.Use(middlewares.NewPrincipalMiddleware())
router.Mount("/api", apiRouter)
userServiceMock := new(mocks.UserServiceMock)
userServiceMock.On("GetUserById", "AdminUser").Return(adminUser, nil)
@@ -61,14 +62,17 @@ func TestUsersHandler_Get(t *testing.T) {
t.Run("when requesting own user data", func(t *testing.T) {
t.Run("should return own data", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/api/compat/wakatime/v1/users/AdminUser", nil)
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/api/compat/wakatime/v1/users/{user}", nil)
req = withUrlParam(req, "user", "AdminUser")
req.Header.Add(
"Authorization",
fmt.Sprintf("Bearer %s", base64.StdEncoding.EncodeToString([]byte(adminUser.ApiKey))),
)
requestRecorder := httptest.NewRecorder()
apiRouter.ServeHTTP(requestRecorder, req)
res := requestRecorder.Result()
router.ServeHTTP(rec, req)
res := rec.Result()
defer res.Body.Close()
data, err := ioutil.ReadAll(res.Body)
@@ -84,14 +88,17 @@ func TestUsersHandler_Get(t *testing.T) {
t.Run("when requesting another users data", func(t *testing.T) {
t.Run("should respond with '401 unauthorized' if not an admin user", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/api/compat/wakatime/v1/users/AdminUser", nil)
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/api/compat/wakatime/v1/users/{user}", nil)
req = withUrlParam(req, "user", "AdminUser")
req.Header.Add(
"Authorization",
fmt.Sprintf("Bearer %s", base64.StdEncoding.EncodeToString([]byte(basicUser.ApiKey))),
)
requestRecorder := httptest.NewRecorder()
apiRouter.ServeHTTP(requestRecorder, req)
res := requestRecorder.Result()
router.ServeHTTP(rec, req)
res := rec.Result()
defer res.Body.Close()
data, err := ioutil.ReadAll(res.Body)
@@ -105,14 +112,17 @@ func TestUsersHandler_Get(t *testing.T) {
})
t.Run("should receive user data if requesting user is an admin", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/api/compat/wakatime/v1/users/BasicUser", nil)
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/api/compat/wakatime/v1/users/{user}", nil)
req = withUrlParam(req, "user", "BasicUser")
req.Header.Add(
"Authorization",
fmt.Sprintf("Bearer %s", base64.StdEncoding.EncodeToString([]byte(adminUser.ApiKey))),
)
requestRecorder := httptest.NewRecorder()
apiRouter.ServeHTTP(requestRecorder, req)
res := requestRecorder.Result()
router.ServeHTTP(rec, req)
res := rec.Result()
defer res.Body.Close()
data, err := ioutil.ReadAll(res.Body)

View File

@@ -1,7 +1,9 @@
package routes
import "github.com/gorilla/mux"
import (
"github.com/go-chi/chi/v5"
)
type Handler interface {
RegisterRoutes(router *mux.Router)
RegisterRoutes(router chi.Router)
}

View File

@@ -4,7 +4,7 @@ import (
"encoding/json"
"fmt"
"github.com/emvi/logbuch"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
"github.com/gorilla/schema"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models"
@@ -33,8 +33,8 @@ func NewHomeHandler(keyValueService services.IKeyValueService) *HomeHandler {
}
}
func (h *HomeHandler) RegisterRoutes(router *mux.Router) {
router.Path("/").Methods(http.MethodGet).HandlerFunc(h.GetIndex)
func (h *HomeHandler) RegisterRoutes(router chi.Router) {
router.Get("/", h.GetIndex)
}
func (h *HomeHandler) GetIndex(w http.ResponseWriter, r *http.Request) {

View File

@@ -1,7 +1,7 @@
package routes
import (
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/models/view"
@@ -21,8 +21,8 @@ func NewImprintHandler(keyValueService services.IKeyValueService) *ImprintHandle
}
}
func (h *ImprintHandler) RegisterRoutes(router *mux.Router) {
router.Path("/imprint").Methods(http.MethodGet).HandlerFunc(h.GetImprint)
func (h *ImprintHandler) RegisterRoutes(router chi.Router) {
router.Get("/imprint", h.GetImprint)
}
func (h *ImprintHandler) GetImprint(w http.ResponseWriter, r *http.Request) {

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
"github.com/emvi/logbuch"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/models"
@@ -34,16 +34,17 @@ func NewLeaderboardHandler(userService services.IUserService, leaderboardService
}
}
func (h *LeaderboardHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/leaderboard").Subrouter()
func (h *LeaderboardHandler) RegisterRoutes(router chi.Router) {
r := chi.NewRouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userService).
WithRedirectTarget(defaultErrorRedirectTarget()).
WithRedirectErrorMessage("unauthorized").
WithOptionalFor([]string{"/"}).
Handler,
WithOptionalFor([]string{"/"}).Handler,
)
r.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
r.Get("/", h.GetIndex)
router.Mount("/leaderboard", r)
}
func (h *LeaderboardHandler) GetIndex(w http.ResponseWriter, r *http.Request) {

View File

@@ -3,7 +3,7 @@ package routes
import (
"fmt"
"github.com/emvi/logbuch"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/models"
@@ -30,24 +30,25 @@ func NewLoginHandler(userService services.IUserService, mailService services.IMa
}
}
func (h *LoginHandler) RegisterRoutes(router *mux.Router) {
router.Path("/login").Methods(http.MethodGet).HandlerFunc(h.GetIndex)
router.Path("/login").Methods(http.MethodPost).HandlerFunc(h.PostLogin)
router.Path("/signup").Methods(http.MethodGet).HandlerFunc(h.GetSignup)
router.Path("/signup").Methods(http.MethodPost).HandlerFunc(h.PostSignup)
router.Path("/set-password").Methods(http.MethodGet).HandlerFunc(h.GetSetPassword)
router.Path("/set-password").Methods(http.MethodPost).HandlerFunc(h.PostSetPassword)
router.Path("/reset-password").Methods(http.MethodGet).HandlerFunc(h.GetResetPassword)
router.Path("/reset-password").Methods(http.MethodPost).HandlerFunc(h.PostResetPassword)
func (h *LoginHandler) RegisterRoutes(router chi.Router) {
router.Get("/login", h.GetIndex)
router.Post("/login", h.PostLogin)
router.Get("/signup", h.GetSignup)
router.Post("/signup", h.PostSignup)
router.Get("/set-password", h.GetSetPassword)
router.Post("/set-password", h.PostSetPassword)
router.Get("/reset-password", h.GetResetPassword)
router.Post("/reset-password", h.PostResetPassword)
authMiddleware := middlewares.NewAuthenticateMiddleware(h.userSrvc).
WithRedirectTarget(defaultErrorRedirectTarget()).
WithRedirectErrorMessage("unauthorized").
WithOptionalFor([]string{"/logout"})
logoutRouter := router.PathPrefix("/logout").Subrouter()
logoutRouter := chi.NewRouter()
logoutRouter.Use(authMiddleware.Handler)
logoutRouter.Path("").Methods(http.MethodPost).HandlerFunc(h.PostLogout)
logoutRouter.Post("/", h.PostLogout)
router.Mount("/logout", logoutRouter)
}
func (h *LoginHandler) GetIndex(w http.ResponseWriter, r *http.Request) {

View File

@@ -1,7 +1,7 @@
package relay
import (
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
conf "github.com/muety/wakapi/config"
"net/http"
"net/http/httputil"
@@ -46,14 +46,16 @@ func (m *filteringMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request)
m.handler.ServeHTTP(w, r)
}
func (h *RelayHandler) RegisterRoutes(router *mux.Router) {
func (h *RelayHandler) RegisterRoutes(router chi.Router) {
if !h.config.Security.EnableProxy {
return
}
r := router.PathPrefix("/relay").Subrouter()
r := chi.NewRouter()
r.Use(newFilteringMiddleware())
r.Path("").HandlerFunc(h.Any)
r.HandleFunc("/", h.Any)
router.Mount("/relay", r)
}
func (h *RelayHandler) Any(w http.ResponseWriter, r *http.Request) {

View File

@@ -3,6 +3,7 @@ package routes
import (
"encoding/base64"
"fmt"
"github.com/go-chi/chi/v5"
"net/http"
"sort"
"strconv"
@@ -11,7 +12,6 @@ import (
datastructure "github.com/duke-git/lancet/v2/datastructure/set"
"github.com/emvi/logbuch"
"github.com/gorilla/mux"
"github.com/gorilla/schema"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
@@ -67,16 +67,17 @@ func NewSettingsHandler(
}
}
func (h *SettingsHandler) RegisterRoutes(router *mux.Router) {
r := router.PathPrefix("/settings").Subrouter()
func (h *SettingsHandler) RegisterRoutes(router chi.Router) {
r := chi.NewRouter()
r.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).
WithRedirectTarget(defaultErrorRedirectTarget()).
WithRedirectErrorMessage("unauthorized").
Handler,
WithRedirectErrorMessage("unauthorized").Handler,
)
r.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
r.Methods(http.MethodPost).HandlerFunc(h.PostIndex)
r.Get("/", h.GetIndex)
r.Post("/", h.PostIndex)
router.Mount("/settings", r)
}
func (h *SettingsHandler) GetIndex(w http.ResponseWriter, r *http.Request) {

View File

@@ -5,7 +5,7 @@ import (
"errors"
"fmt"
"github.com/emvi/logbuch"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/models"
@@ -70,25 +70,27 @@ func NewSubscriptionHandler(
// https://stripe.com/docs/billing/quickstart?lang=go
func (h *SubscriptionHandler) RegisterRoutes(router *mux.Router) {
func (h *SubscriptionHandler) RegisterRoutes(router chi.Router) {
if !h.config.Subscriptions.Enabled {
return
}
subRouterPublic := router.PathPrefix("/subscription").Subrouter()
subRouterPublic.Path("/success").Methods(http.MethodGet).HandlerFunc(h.GetCheckoutSuccess)
subRouterPublic.Path("/cancel").Methods(http.MethodGet).HandlerFunc(h.GetCheckoutCancel)
subRouterPublic.Path("/webhook").Methods(http.MethodPost).HandlerFunc(h.PostWebhook)
subRouterPublic := chi.NewRouter()
subRouterPublic.Get("/success", h.GetCheckoutSuccess)
subRouterPublic.Get("/cancel", h.GetCheckoutCancel)
subRouterPublic.Post("/webhook", h.PostWebhook)
subRouterPrivate := subRouterPublic.PathPrefix("").Subrouter()
subRouterPrivate := chi.NewRouter()
subRouterPrivate.Use(
middlewares.NewAuthenticateMiddleware(h.userSrvc).
WithRedirectTarget(defaultErrorRedirectTarget()).
WithRedirectErrorMessage("unauthorized").
Handler,
WithRedirectErrorMessage("unauthorized").Handler,
)
subRouterPrivate.Path("/checkout").Methods(http.MethodPost).HandlerFunc(h.PostCheckout)
subRouterPrivate.Path("/portal").Methods(http.MethodPost).HandlerFunc(h.PostPortal)
subRouterPrivate.Post("/checkout", h.PostCheckout)
subRouterPrivate.Post("/portal", h.PostPortal)
subRouterPublic.Mount("/", subRouterPrivate)
router.Mount("/subscription", subRouterPublic)
}
func (h *SubscriptionHandler) PostCheckout(w http.ResponseWriter, r *http.Request) {

View File

@@ -2,7 +2,7 @@ package routes
import (
"fmt"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/helpers"
"github.com/muety/wakapi/middlewares"
@@ -30,20 +30,15 @@ func NewSummaryHandler(summaryService services.ISummaryService, userService serv
}
}
func (h *SummaryHandler) RegisterRoutes(router *mux.Router) {
r1 := router.PathPrefix("/summary").Subrouter()
r1.Use(middlewares.NewAuthenticateMiddleware(h.userSrvc).
func (h *SummaryHandler) RegisterRoutes(router chi.Router) {
r := chi.NewRouter()
r.Use(middlewares.NewAuthenticateMiddleware(h.userSrvc).
WithRedirectTarget(defaultErrorRedirectTarget()).
WithRedirectErrorMessage("unauthorized").
Handler)
r1.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
WithRedirectErrorMessage("unauthorized").Handler,
)
r.Get("/", h.GetIndex)
r2 := router.PathPrefix("/summary").Subrouter()
r2.Use(middlewares.NewAuthenticateMiddleware(h.userSrvc).
WithRedirectTarget(defaultErrorRedirectTarget()).
WithRedirectErrorMessage("unauthorized").
Handler)
r2.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
router.Mount("/summary", r)
}
func (h *SummaryHandler) GetIndex(w http.ResponseWriter, r *http.Request) {

View File

@@ -2,7 +2,7 @@ package utils
import (
"errors"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/models"
@@ -20,24 +20,23 @@ func CheckEffectiveUser(w http.ResponseWriter, r *http.Request, userService serv
return nil, err
}
var vars = mux.Vars(r)
if vars["user"] == "" {
vars["user"] = fallback
userParam := chi.URLParam(r, "user")
if userParam == "" {
userParam = fallback
}
authorizedUser := middlewares.GetPrincipal(r)
if authorizedUser == nil {
return respondError(http.StatusUnauthorized, conf.ErrUnauthorized)
} else if vars["user"] == "current" {
} else if userParam == "current" {
return authorizedUser, nil
}
if authorizedUser.ID != vars["user"] && !authorizedUser.IsAdmin {
if authorizedUser.ID != userParam && !authorizedUser.IsAdmin {
return respondError(http.StatusUnauthorized, conf.ErrUnauthorized)
}
requestedUser, err := userService.GetUserById(vars["user"])
requestedUser, err := userService.GetUserById(userParam)
if err != nil {
return respondError(http.StatusNotFound, "user not found")
}

View File

@@ -2,14 +2,14 @@ package utils
import (
"context"
"fmt"
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/mocks"
"github.com/muety/wakapi/models"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
@@ -70,8 +70,8 @@ func mockUserAwareRequest(requestedUser, authorizedUser string) (*http.Request,
testPrincipal.SetPrincipal(&testUser)
}
r := httptest.NewRequest("GET", fmt.Sprintf("http://localhost:3000/api/%s/data", requestedUser), nil)
r = mux.SetURLVars(r, map[string]string{"user": requestedUser})
r := httptest.NewRequest("GET", "http://localhost:3000/api/{user}/data", nil)
r = withUrlParam(r, "user", requestedUser)
r = r.WithContext(context.WithValue(r.Context(), "principal", &testPrincipal))
userServiceMock := new(mocks.UserServiceMock)
@@ -81,3 +81,12 @@ func mockUserAwareRequest(requestedUser, authorizedUser string) (*http.Request,
return r, httptest.NewRecorder(), userServiceMock
}
func withUrlParam(r *http.Request, key, value string) *http.Request {
r.URL.RawPath = strings.Replace(r.URL.RawPath, "{"+key+"}", value, 1)
r.URL.Path = strings.Replace(r.URL.Path, "{"+key+"}", value, 1)
rctx := chi.NewRouteContext()
rctx.URLParams.Add(key, value)
r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))
return r
}