Added redirect package.
This commit is contained in:
parent
8cae6e6beb
commit
a70003d290
6 changed files with 208 additions and 82 deletions
91
pkg/redirect/redirect.go
Normal file
91
pkg/redirect/redirect.go
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
package redirect
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/mikestefanello/pagoda/pkg/htmx"
|
||||
)
|
||||
|
||||
// Redirect is a helper to perform HTTP redirects.
|
||||
type Redirect struct {
|
||||
ctx echo.Context
|
||||
url string
|
||||
routeName string
|
||||
routeParams []any
|
||||
status int
|
||||
query url.Values
|
||||
}
|
||||
|
||||
// New initializes a new Redirect
|
||||
func New(ctx echo.Context) *Redirect {
|
||||
return &Redirect{
|
||||
ctx: ctx,
|
||||
status: http.StatusFound,
|
||||
}
|
||||
}
|
||||
|
||||
// Route sets the route name to redirect to.
|
||||
// Use either this or URL()
|
||||
func (r *Redirect) Route(name string) *Redirect {
|
||||
r.routeName = name
|
||||
return r
|
||||
}
|
||||
|
||||
// Params sets the route params
|
||||
func (r *Redirect) Params(params ...any) *Redirect {
|
||||
r.routeParams = params
|
||||
return r
|
||||
}
|
||||
|
||||
// StatusCode sets the HTTP status code which defaults to http.StatusFound.
|
||||
// Does not apply to HTMX redirects.
|
||||
func (r *Redirect) StatusCode(code int) *Redirect {
|
||||
r.status = code
|
||||
return r
|
||||
}
|
||||
|
||||
// Query sets a URL query
|
||||
func (r *Redirect) Query(query url.Values) *Redirect {
|
||||
r.query = query
|
||||
return r
|
||||
}
|
||||
|
||||
// URL sets the URL to redirect to
|
||||
// Use either this or Route()
|
||||
func (r *Redirect) URL(url string) *Redirect {
|
||||
r.url = url
|
||||
return r
|
||||
}
|
||||
|
||||
// Go performs the redirect
|
||||
// If the request is HTMX boosted, an HTMX redirect will be performed instead of an HTTP redirect
|
||||
func (r *Redirect) Go() error {
|
||||
if r.routeName == "" && r.url == "" {
|
||||
return errors.New("no redirect provided")
|
||||
}
|
||||
|
||||
var dest string
|
||||
if r.url != "" {
|
||||
dest = r.url
|
||||
} else {
|
||||
dest = r.ctx.Echo().Reverse(r.routeName, r.routeParams...)
|
||||
}
|
||||
|
||||
if len(r.query) > 0 {
|
||||
dest = fmt.Sprintf("%s?%s", dest, r.query.Encode())
|
||||
}
|
||||
|
||||
if htmx.GetRequest(r.ctx).Boosted {
|
||||
htmx.Response{
|
||||
Redirect: dest,
|
||||
}.Apply(r.ctx)
|
||||
|
||||
return nil
|
||||
} else {
|
||||
return r.ctx.Redirect(r.status, dest)
|
||||
}
|
||||
}
|
||||
77
pkg/redirect/redirect_test.go
Normal file
77
pkg/redirect/redirect_test.go
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
package redirect
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/mikestefanello/pagoda/pkg/htmx"
|
||||
"github.com/mikestefanello/pagoda/pkg/tests"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRedirect(t *testing.T) {
|
||||
e := echo.New()
|
||||
e.GET("/path/:first/and/:second", func(c echo.Context) error {
|
||||
return nil
|
||||
}).Name = "test"
|
||||
|
||||
redirect := func() (*Redirect, echo.Context) {
|
||||
ctx, _ := tests.NewContext(e, "/")
|
||||
return New(ctx), ctx
|
||||
}
|
||||
|
||||
t.Run("route", func(t *testing.T) {
|
||||
q := url.Values{}
|
||||
q.Add("a", "1")
|
||||
q.Add("b", "2")
|
||||
r, ctx := redirect()
|
||||
r.Route("test")
|
||||
r.Params("one", "two")
|
||||
r.Query(q)
|
||||
r.StatusCode(http.StatusTemporaryRedirect)
|
||||
require.NoError(t, r.Go())
|
||||
assert.Equal(t, "/path/one/and/two?a=1&b=2", ctx.Response().Header().Get(echo.HeaderLocation))
|
||||
assert.Equal(t, http.StatusTemporaryRedirect, ctx.Response().Status)
|
||||
})
|
||||
|
||||
t.Run("route htmx", func(t *testing.T) {
|
||||
q := url.Values{}
|
||||
q.Add("a", "1")
|
||||
q.Add("b", "2")
|
||||
r, ctx := redirect()
|
||||
ctx.Request().Header.Set(htmx.HeaderBoosted, "true")
|
||||
r.Route("test")
|
||||
r.Params("one", "two")
|
||||
r.Query(q)
|
||||
require.NoError(t, r.Go())
|
||||
assert.Equal(t, "/path/one/and/two?a=1&b=2", ctx.Response().Header().Get(htmx.HeaderRedirect))
|
||||
})
|
||||
|
||||
t.Run("url", func(t *testing.T) {
|
||||
q := url.Values{}
|
||||
q.Add("a", "1")
|
||||
q.Add("b", "2")
|
||||
r, ctx := redirect()
|
||||
r.URL("https://localhost.dev")
|
||||
r.Query(q)
|
||||
r.StatusCode(http.StatusTemporaryRedirect)
|
||||
require.NoError(t, r.Go())
|
||||
assert.Equal(t, "https://localhost.dev?a=1&b=2", ctx.Response().Header().Get(echo.HeaderLocation))
|
||||
assert.Equal(t, http.StatusTemporaryRedirect, ctx.Response().Status)
|
||||
})
|
||||
|
||||
t.Run("url htmx", func(t *testing.T) {
|
||||
q := url.Values{}
|
||||
q.Add("a", "1")
|
||||
q.Add("b", "2")
|
||||
r, ctx := redirect()
|
||||
ctx.Request().Header.Set(htmx.HeaderBoosted, "true")
|
||||
r.URL("https://localhost.dev")
|
||||
r.Query(q)
|
||||
require.NoError(t, r.Go())
|
||||
assert.Equal(t, "https://localhost.dev?a=1&b=2", ctx.Response().Header().Get(htmx.HeaderRedirect))
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue