1
0
mirror of https://github.com/volatiletech/authboss.git synced 2024-11-28 08:58:38 +02:00
authboss/defaults/responder.go
2018-09-27 22:06:56 -07:00

140 lines
3.4 KiB
Go

package defaults
import (
"net/http"
"strings"
"github.com/volatiletech/authboss"
)
// Responder helps respond to http requests
type Responder struct {
Renderer authboss.Renderer
}
// NewResponder constructor
func NewResponder(renderer authboss.Renderer) *Responder {
return &Responder{Renderer: renderer}
}
// Respond to an HTTP request. It's main job is to merge data that comes in from
// various middlewares via the context with the data sent by the controller and
// render that.
func (r *Responder) Respond(w http.ResponseWriter, req *http.Request, code int, page string, data authboss.HTMLData) error {
ctxData := req.Context().Value(authboss.CTXKeyData)
if ctxData != nil {
if data == nil {
data = authboss.HTMLData{}
}
data.Merge(ctxData.(authboss.HTMLData))
}
rendered, mime, err := r.Renderer.Render(req.Context(), page, data)
if err != nil {
return err
}
w.Header().Set("Content-Type", mime)
w.WriteHeader(code)
_, err = w.Write(rendered)
return err
}
func isAPIRequest(r *http.Request) bool {
return strings.HasPrefix(r.Header.Get("Content-Type"), "application/json")
}
// Redirector for http requests
type Redirector struct {
Renderer authboss.Renderer
// FormValueName for the redirection
FormValueName string
// CoerceRedirectTo200 forces http.StatusTemporaryRedirect and
// and http.StatusPermanentRedirect to http.StatusOK
CorceRedirectTo200 bool
}
// NewRedirector constructor
func NewRedirector(renderer authboss.Renderer, formValueName string) *Redirector {
return &Redirector{FormValueName: formValueName, Renderer: renderer}
}
// Redirect the client elsewhere. If it's an API request it will simply render
// a JSON response with information that should help a client to decide what
// to do.
func (r *Redirector) Redirect(w http.ResponseWriter, req *http.Request, ro authboss.RedirectOptions) error {
var redirectFunction = r.redirectNonAPI
if isAPIRequest(req) {
redirectFunction = r.redirectAPI
}
return redirectFunction(w, req, ro)
}
func (r Redirector) redirectAPI(w http.ResponseWriter, req *http.Request, ro authboss.RedirectOptions) error {
path := ro.RedirectPath
redir := req.FormValue(r.FormValueName)
if len(redir) != 0 && ro.FollowRedirParam {
path = redir
}
var status = "success"
var message string
if len(ro.Success) != 0 {
message = ro.Success
}
if len(ro.Failure) != 0 {
status = "failure"
message = ro.Failure
}
data := authboss.HTMLData{
"location": path,
}
data["status"] = status
if len(message) != 0 {
data["message"] = message
}
body, mime, err := r.Renderer.Render(req.Context(), "redirect", data)
if err != nil {
return err
}
if len(body) != 0 {
w.Header().Set("Content-Type", mime)
}
if ro.Code != 0 {
if r.CorceRedirectTo200 && (ro.Code == http.StatusTemporaryRedirect || ro.Code == http.StatusPermanentRedirect) {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(ro.Code)
}
}
_, err = w.Write(body)
return err
}
func (r Redirector) redirectNonAPI(w http.ResponseWriter, req *http.Request, ro authboss.RedirectOptions) error {
path := ro.RedirectPath
redir := req.FormValue(r.FormValueName)
if len(redir) != 0 && ro.FollowRedirParam {
path = redir
}
if len(ro.Success) != 0 {
authboss.PutSession(w, authboss.FlashSuccessKey, ro.Success)
}
if len(ro.Failure) != 0 {
authboss.PutSession(w, authboss.FlashErrorKey, ro.Failure)
}
http.Redirect(w, req, path, http.StatusFound)
return nil
}