Skip to content

Commit

Permalink
website/api/v1: implement request route
Browse files Browse the repository at this point in the history
templates: added HasField method that indicates if the first argument has
a field named after the second.

util: implement RedirectToServer that uses http.ServerContextKey to get
the *http.Server used for the request and passes its arguments back into
its srv.Handler.ServeHTTP method.

templates: theme middleware now uses util.RedirectToServer

util: implement ChangeRequestMethod
  • Loading branch information
Wessie committed Apr 29, 2024
1 parent 790224e commit 27fed0c
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 10 deletions.
8 changes: 8 additions & 0 deletions templates/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"html/template"
"reflect"
"time"

radio "github.com/R-a-dio/valkyrie"
Expand All @@ -30,6 +31,13 @@ var fnMap = map[string]any{
"Sub": func(a, b int64) int64 { return a - b },
"CalculateSubmissionCooldown": radio.CalculateSubmissionCooldown,
"AllUserPermissions": radio.AllUserPermissions,
"HasField": HasField,
}

func HasField(v any, name string) bool {
rv := reflect.ValueOf(v)
rv = reflect.Indirect(rv)
return rv.FieldByName(name).IsValid()
}

func PrintJSON(v any) (template.HTML, error) {
Expand Down
8 changes: 3 additions & 5 deletions templates/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,11 @@ func SetThemeHandler(cookieName string, resolve func(string) string) http.Handle
// and change the theme so the new page actually uses our new theme set
r = r.WithContext(SetTheme(r.Context(), theme, true))

srv := r.Context().Value(http.ServerContextKey)
if srv == nil {
hlog.FromRequest(r).Error().Msg("SetThemeHandler used with no server")
err := util.RedirectToServer(w, r)
if err != nil {
hlog.FromRequest(r).Error().Err(err).Msg("SetThemeHandler")
w.WriteHeader(http.StatusOK)
return
}

srv.(*http.Server).Handler.ServeHTTP(w, r)
})
}
63 changes: 58 additions & 5 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"sync/atomic"
"time"

"github.com/R-a-dio/valkyrie/errors"
"github.com/R-a-dio/valkyrie/util/eventstream"
"github.com/go-chi/chi/v5"
"github.com/rs/zerolog"
Expand All @@ -33,13 +34,21 @@ func IsHTMX(r *http.Request) bool {
}

func RedirectBack(r *http.Request) *http.Request {
current, err := url.Parse(r.Header.Get("Hx-Current-Url"))
if err == nil {
r.URL = current
} else {
current, err = url.Parse(r.Referer())
var changed bool

if hxHeader := r.Header.Get("Hx-Current-Url"); hxHeader != "" {
current, err := url.Parse(hxHeader)
if err == nil {
r.URL = current
changed = true
}
}

if !changed {
current, err := url.Parse(r.Referer())
if err == nil {
r.URL = current
changed = true
}
}

Expand All @@ -56,6 +65,50 @@ func RedirectBack(r *http.Request) *http.Request {
return r
}

func ChangeRequestMethod(r *http.Request, method string) *http.Request {
r.Method = method

rCtx := r.Context().Value(chi.RouteCtxKey)
if rCtx != nil {
if chiCtx, ok := rCtx.(*chi.Context); ok {
chiCtx.RouteMethod = method
}
}

return r
}

type alreadyRedirectedKey struct{}

// RedirectToServer looks up the http.Server associated with this request
// and calls ServeHTTP again
func RedirectToServer(w http.ResponseWriter, r *http.Request) error {
const op errors.Op = "util.RedirectToServer"
ctx := r.Context()

alreadyRedirected := ctx.Value(alreadyRedirectedKey{})
if alreadyRedirected != nil {
return errors.E(op, "request was already redirected once")
}

srv := ctx.Value(http.ServerContextKey)
if srv == nil {
return errors.E(op, "no server context key found")
}

httpSrv, ok := srv.(*http.Server)
if !ok {
return errors.E(op, "server context key did not contain *http.Server")
}

// add a context value so we know we've redirected internally
ctx = context.WithValue(r.Context(), alreadyRedirectedKey{}, struct{}{})

// and then send them off to be handled again
httpSrv.Handler.ServeHTTP(w, r.WithContext(ctx))
return nil
}

func AbsolutePath(dir string, path string) string {
if filepath.IsAbs(path) {
return path
Expand Down
1 change: 1 addition & 0 deletions website/api/v1/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,5 @@ func (a *API) Route(r chi.Router) {
r.Get("/sse", a.sse.ServeHTTP)
r.Get("/search", a.SearchHTML)
r.Get("/song", a.GetSong)
r.Post("/request", a.PostRequest)

Check failure on line 65 in website/api/v1/router.go

View workflow job for this annotation

GitHub Actions / test

a.PostRequest undefined (type *API has no field or method PostRequest)
}

0 comments on commit 27fed0c

Please sign in to comment.