Small fixes
This commit is contained in:
parent
baada0dae5
commit
e59a973228
|
@ -5,8 +5,9 @@ import (
|
|||
)
|
||||
|
||||
type AuthData struct {
|
||||
User string
|
||||
Group string
|
||||
User string
|
||||
Group string
|
||||
Properties map[string]string
|
||||
}
|
||||
|
||||
type AuthManager interface {
|
||||
|
|
82
context.go
82
context.go
|
@ -5,6 +5,7 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.thirdmartini.com/pub/snap/auth"
|
||||
)
|
||||
|
@ -19,9 +20,11 @@ type Context struct {
|
|||
}
|
||||
|
||||
type SnapContent struct {
|
||||
User string
|
||||
Theme string
|
||||
Content interface{}
|
||||
User string
|
||||
UserProperties map[string]string
|
||||
Theme string
|
||||
Meta map[string]string
|
||||
Content interface{}
|
||||
}
|
||||
|
||||
func (c *Context) GetRequest() *http.Request {
|
||||
|
@ -43,14 +46,32 @@ func (c *Context) Error(code int, msg string) {
|
|||
c.srv.renderError(c.w, code, msg)
|
||||
}
|
||||
|
||||
func (c *Context) ErrorObject(code int, obj interface{}) {
|
||||
msg, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
c.Error(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
}
|
||||
c.Error(code, string(msg))
|
||||
}
|
||||
|
||||
func (c *Context) Reply(msg string) {
|
||||
c.srv.reply(c.w, msg)
|
||||
}
|
||||
|
||||
func (c *Context) ReplyWithHeaders(msg string, kv map[string]string) {
|
||||
h := c.w.Header()
|
||||
for k, v := range kv {
|
||||
h.Add(k, v)
|
||||
}
|
||||
c.srv.reply(c.w, msg)
|
||||
}
|
||||
|
||||
func (c *Context) ReplyObject(obj interface{}) {
|
||||
msg, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
c.Error(400, "Internal Server Error")
|
||||
c.Error(http.StatusInternalServerError, "Internal Server Error")
|
||||
return
|
||||
}
|
||||
c.Reply(string(msg))
|
||||
}
|
||||
|
@ -72,11 +93,38 @@ func (c *Context) RenderEx(tmpl string, content interface{}) {
|
|||
cnt := SnapContent{
|
||||
User: c.GetUser(),
|
||||
Theme: c.srv.theme,
|
||||
Meta: c.srv.meta,
|
||||
Content: content,
|
||||
}
|
||||
c.srv.render(c.w, tmpl, &cnt)
|
||||
}
|
||||
|
||||
func (c *Context) RenderWithMeta(tmpl string, meta map[string]string, content interface{}) {
|
||||
// Merge metas
|
||||
if meta == nil {
|
||||
meta = make(map[string]string)
|
||||
}
|
||||
|
||||
for k, v := range c.srv.meta {
|
||||
if _, ok := meta[k]; !ok {
|
||||
meta[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
cnt := SnapContent{
|
||||
User: c.GetUser(),
|
||||
Theme: c.srv.theme,
|
||||
Meta: meta,
|
||||
Content: content,
|
||||
}
|
||||
|
||||
if c.auth != nil {
|
||||
cnt.UserProperties = c.auth.Properties
|
||||
}
|
||||
|
||||
c.srv.render(c.w, tmpl, &cnt)
|
||||
}
|
||||
|
||||
func (c *Context) GetVar(k string) (string, bool) {
|
||||
v, ok := c.vars[k]
|
||||
return v, ok
|
||||
|
@ -90,6 +138,18 @@ func (c *Context) GetVarDefault(k string, def string) string {
|
|||
return v
|
||||
}
|
||||
|
||||
func (c *Context) GetVarAsSlice(k string, delim string, def []string) []string {
|
||||
v, ok := c.vars[k]
|
||||
if !ok {
|
||||
return def
|
||||
}
|
||||
r := strings.Split(v, delim)
|
||||
if len(r) == 1 && r[0] == "" {
|
||||
return def
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (c *Context) ParseForm() error {
|
||||
return c.r.ParseForm()
|
||||
}
|
||||
|
@ -109,6 +169,15 @@ func (c *Context) FormValueUint64(k string) uint64 {
|
|||
return val
|
||||
}
|
||||
|
||||
func (c *Context) FormValueAsSlice(k string, delim string) []string {
|
||||
v := c.r.FormValue(k)
|
||||
r := strings.Split(v, delim)
|
||||
if len(r) == 1 && r[0] == "" {
|
||||
return []string{}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func (c *Context) Redirect(url string) {
|
||||
http.Redirect(c.w, c.r, url, http.StatusSeeOther)
|
||||
}
|
||||
|
@ -117,6 +186,11 @@ func (c *Context) QueryValue(key string) string {
|
|||
return c.r.URL.Query().Get(key)
|
||||
}
|
||||
|
||||
func (c *Context) QueryHas(key string) bool {
|
||||
_, ok := c.r.URL.Query()[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (c *Context) QueryValueWithDefault(key string, def string) string {
|
||||
val := c.r.URL.Query().Get(key)
|
||||
if val == "" {
|
||||
|
|
117
server.go
117
server.go
|
@ -20,15 +20,17 @@ import (
|
|||
)
|
||||
|
||||
type Server struct {
|
||||
address string
|
||||
theme string
|
||||
debug bool
|
||||
fs http.FileSystem
|
||||
auth auth.Authenticator
|
||||
router *mux.Router
|
||||
templates string
|
||||
cachedTmpl *template.Template
|
||||
address string
|
||||
theme string
|
||||
debug bool
|
||||
fs http.FileSystem
|
||||
auth auth.Authenticator
|
||||
router *mux.Router
|
||||
templates string
|
||||
cachedTmpl *template.Template
|
||||
templateFuncs template.FuncMap
|
||||
|
||||
meta map[string]string
|
||||
// testModeEnabled if test mode is enabled we will not render the template but jsut return the
|
||||
// json object
|
||||
testModeEnabled bool
|
||||
|
@ -39,6 +41,14 @@ type SnapBaseContent struct {
|
|||
Content interface{}
|
||||
}
|
||||
|
||||
func noescape(str string) template.HTML {
|
||||
return template.HTML(str)
|
||||
}
|
||||
|
||||
var builtinFuncMap = template.FuncMap{
|
||||
"noescape": noescape,
|
||||
}
|
||||
|
||||
func (s *Server) makeContext(auth *auth.AuthData, w http.ResponseWriter, r *http.Request) *Context {
|
||||
c := &Context{
|
||||
r: r,
|
||||
|
@ -50,9 +60,30 @@ func (s *Server) makeContext(auth *auth.AuthData, w http.ResponseWriter, r *http
|
|||
return c
|
||||
}
|
||||
|
||||
func (s *Server) withLoginHandler(auth auth.Authenticator, loginHandler func(c *Context) bool, handle func(c *Context)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if s.debug {
|
||||
log.Debug("authenticated request with login ui handler: ", r.RequestURI)
|
||||
}
|
||||
rec, ok := auth.DoAuth(w, r)
|
||||
if !ok {
|
||||
log.Debug("authenticated request with login ui handler to login ", r.RequestURI)
|
||||
c := s.makeContext(rec, w, r)
|
||||
if loginHandler(c) {
|
||||
handle(c)
|
||||
}
|
||||
} else {
|
||||
c := s.makeContext(rec, w, r)
|
||||
handle(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) authenticated(auth auth.Authenticator, redirect string, handle func(c *Context)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Debug("authenticated request: ", r.RequestURI)
|
||||
if s.debug {
|
||||
log.Debug("authenticated request: ", r.RequestURI)
|
||||
}
|
||||
|
||||
rec, ok := auth.DoAuth(w, r)
|
||||
if !ok {
|
||||
|
@ -70,7 +101,9 @@ func (s *Server) authenticated(auth auth.Authenticator, redirect string, handle
|
|||
|
||||
func (s *Server) wrapper(handle func(c *Context)) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
log.Debug("request: ", r.RequestURI)
|
||||
if s.debug {
|
||||
log.Debug("request: ", r.RequestURI)
|
||||
}
|
||||
|
||||
c := s.makeContext(nil, w, r)
|
||||
if s.auth != nil {
|
||||
|
@ -119,7 +152,7 @@ func (s *Server) parseTemplates(t *template.Template, filenames ...string) (*tem
|
|||
// works. Otherwise we create a new template associated with t.
|
||||
var tmpl *template.Template
|
||||
if t == nil {
|
||||
t = template.New(name)
|
||||
t = template.New(name).Funcs(s.templateFuncs)
|
||||
}
|
||||
if name == t.Name() {
|
||||
tmpl = t
|
||||
|
@ -165,7 +198,7 @@ func Walk(fs http.FileSystem, base string, walkFunc func(path string, info os.Fi
|
|||
}
|
||||
|
||||
func (s *Server) LoadTemplatesFS(fs http.FileSystem, base string) (*template.Template, error) {
|
||||
tmpl := template.New("")
|
||||
tmpl := template.New("").Funcs(s.templateFuncs)
|
||||
|
||||
err := Walk(fs, base, func(path string, info os.FileInfo, err error) error {
|
||||
if strings.Contains(path, ".html") {
|
||||
|
@ -236,6 +269,13 @@ func (s *Server) HandleFuncAuthenticated(path, redirect string, f func(c *Contex
|
|||
return s.router.HandleFunc(path, s.authenticated(s.auth, redirect, f))
|
||||
}
|
||||
|
||||
func (s *Server) HandleFuncAuthenticatedWithLogin(path string, loginHandler func(c *Context) bool, contentHandler func(c *Context)) *mux.Route {
|
||||
if s.auth == nil {
|
||||
return nil
|
||||
}
|
||||
return s.router.HandleFunc(path, s.withLoginHandler(s.auth, loginHandler, contentHandler))
|
||||
}
|
||||
|
||||
func (s *Server) HandleFuncCustomAuth(auth auth.Authenticator, path, redirect string, f func(c *Context)) *mux.Route {
|
||||
if auth == nil {
|
||||
log.Warn("Nil auth on", path)
|
||||
|
@ -318,6 +358,45 @@ func (s *Server) WithDebug(debugURL string) *Server {
|
|||
return s
|
||||
}
|
||||
|
||||
func (s *Server) WithMetadata(meta map[string]string) *Server {
|
||||
s.meta = meta
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) WithTemplateFuncs(funcs template.FuncMap) *Server {
|
||||
for k, f := range funcs {
|
||||
s.templateFuncs[k] = f
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) WithAuth(auth auth.Authenticator) *Server {
|
||||
s.auth = auth
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) WithHealthCheck(version, date string, status func() (bool, string)) {
|
||||
s.HandleFunc("/_health", func(c *Context) {
|
||||
ok, msg := status()
|
||||
|
||||
hc := struct {
|
||||
Version string
|
||||
Date string
|
||||
Status string
|
||||
}{
|
||||
Version: version,
|
||||
Date: date,
|
||||
Status: msg,
|
||||
}
|
||||
|
||||
if ok {
|
||||
c.ReplyObject(&hc)
|
||||
return
|
||||
}
|
||||
c.ErrorObject(http.StatusServiceUnavailable, &hc)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) Dump() {
|
||||
fmt.Printf(" Theme: %s\n", s.theme)
|
||||
fmt.Printf(" Templates: %s\n", s.templates)
|
||||
|
@ -325,12 +404,14 @@ func (s *Server) Dump() {
|
|||
|
||||
func New(address string, path string, auth auth.Authenticator) *Server {
|
||||
s := Server{
|
||||
router: mux.NewRouter(),
|
||||
auth: auth,
|
||||
address: address,
|
||||
fs: http.FileSystem(http.Dir(path)),
|
||||
templates: "/templates",
|
||||
theme: "/static/css/default.css",
|
||||
router: mux.NewRouter(),
|
||||
auth: auth,
|
||||
address: address,
|
||||
fs: http.FileSystem(http.Dir(path)),
|
||||
templates: "/templates",
|
||||
templateFuncs: builtinFuncMap,
|
||||
theme: "/static/css/default.css",
|
||||
meta: make(map[string]string),
|
||||
}
|
||||
return &s
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package snap
|
||||
|
||||
func Redirect(to string) func(c *Context) {
|
||||
return func(c *Context) {
|
||||
c.Redirect(to)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue