Small fixes
This commit is contained in:
parent
baada0dae5
commit
e59a973228
|
@ -5,8 +5,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthData struct {
|
type AuthData struct {
|
||||||
User string
|
User string
|
||||||
Group string
|
Group string
|
||||||
|
Properties map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthManager interface {
|
type AuthManager interface {
|
||||||
|
|
82
context.go
82
context.go
|
@ -5,6 +5,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"git.thirdmartini.com/pub/snap/auth"
|
"git.thirdmartini.com/pub/snap/auth"
|
||||||
)
|
)
|
||||||
|
@ -19,9 +20,11 @@ type Context struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SnapContent struct {
|
type SnapContent struct {
|
||||||
User string
|
User string
|
||||||
Theme string
|
UserProperties map[string]string
|
||||||
Content interface{}
|
Theme string
|
||||||
|
Meta map[string]string
|
||||||
|
Content interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) GetRequest() *http.Request {
|
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)
|
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) {
|
func (c *Context) Reply(msg string) {
|
||||||
c.srv.reply(c.w, msg)
|
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{}) {
|
func (c *Context) ReplyObject(obj interface{}) {
|
||||||
msg, err := json.Marshal(obj)
|
msg, err := json.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Error(400, "Internal Server Error")
|
c.Error(http.StatusInternalServerError, "Internal Server Error")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
c.Reply(string(msg))
|
c.Reply(string(msg))
|
||||||
}
|
}
|
||||||
|
@ -72,11 +93,38 @@ func (c *Context) RenderEx(tmpl string, content interface{}) {
|
||||||
cnt := SnapContent{
|
cnt := SnapContent{
|
||||||
User: c.GetUser(),
|
User: c.GetUser(),
|
||||||
Theme: c.srv.theme,
|
Theme: c.srv.theme,
|
||||||
|
Meta: c.srv.meta,
|
||||||
Content: content,
|
Content: content,
|
||||||
}
|
}
|
||||||
c.srv.render(c.w, tmpl, &cnt)
|
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) {
|
func (c *Context) GetVar(k string) (string, bool) {
|
||||||
v, ok := c.vars[k]
|
v, ok := c.vars[k]
|
||||||
return v, ok
|
return v, ok
|
||||||
|
@ -90,6 +138,18 @@ func (c *Context) GetVarDefault(k string, def string) string {
|
||||||
return v
|
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 {
|
func (c *Context) ParseForm() error {
|
||||||
return c.r.ParseForm()
|
return c.r.ParseForm()
|
||||||
}
|
}
|
||||||
|
@ -109,6 +169,15 @@ func (c *Context) FormValueUint64(k string) uint64 {
|
||||||
return val
|
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) {
|
func (c *Context) Redirect(url string) {
|
||||||
http.Redirect(c.w, c.r, url, http.StatusSeeOther)
|
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)
|
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 {
|
func (c *Context) QueryValueWithDefault(key string, def string) string {
|
||||||
val := c.r.URL.Query().Get(key)
|
val := c.r.URL.Query().Get(key)
|
||||||
if val == "" {
|
if val == "" {
|
||||||
|
|
117
server.go
117
server.go
|
@ -20,15 +20,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
address string
|
address string
|
||||||
theme string
|
theme string
|
||||||
debug bool
|
debug bool
|
||||||
fs http.FileSystem
|
fs http.FileSystem
|
||||||
auth auth.Authenticator
|
auth auth.Authenticator
|
||||||
router *mux.Router
|
router *mux.Router
|
||||||
templates string
|
templates string
|
||||||
cachedTmpl *template.Template
|
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
|
// testModeEnabled if test mode is enabled we will not render the template but jsut return the
|
||||||
// json object
|
// json object
|
||||||
testModeEnabled bool
|
testModeEnabled bool
|
||||||
|
@ -39,6 +41,14 @@ type SnapBaseContent struct {
|
||||||
Content interface{}
|
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 {
|
func (s *Server) makeContext(auth *auth.AuthData, w http.ResponseWriter, r *http.Request) *Context {
|
||||||
c := &Context{
|
c := &Context{
|
||||||
r: r,
|
r: r,
|
||||||
|
@ -50,9 +60,30 @@ func (s *Server) makeContext(auth *auth.AuthData, w http.ResponseWriter, r *http
|
||||||
return c
|
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 {
|
func (s *Server) authenticated(auth auth.Authenticator, redirect string, handle func(c *Context)) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
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)
|
rec, ok := auth.DoAuth(w, r)
|
||||||
if !ok {
|
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 {
|
func (s *Server) wrapper(handle func(c *Context)) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
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)
|
c := s.makeContext(nil, w, r)
|
||||||
if s.auth != nil {
|
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.
|
// works. Otherwise we create a new template associated with t.
|
||||||
var tmpl *template.Template
|
var tmpl *template.Template
|
||||||
if t == nil {
|
if t == nil {
|
||||||
t = template.New(name)
|
t = template.New(name).Funcs(s.templateFuncs)
|
||||||
}
|
}
|
||||||
if name == t.Name() {
|
if name == t.Name() {
|
||||||
tmpl = t
|
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) {
|
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 {
|
err := Walk(fs, base, func(path string, info os.FileInfo, err error) error {
|
||||||
if strings.Contains(path, ".html") {
|
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))
|
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 {
|
func (s *Server) HandleFuncCustomAuth(auth auth.Authenticator, path, redirect string, f func(c *Context)) *mux.Route {
|
||||||
if auth == nil {
|
if auth == nil {
|
||||||
log.Warn("Nil auth on", path)
|
log.Warn("Nil auth on", path)
|
||||||
|
@ -318,6 +358,45 @@ func (s *Server) WithDebug(debugURL string) *Server {
|
||||||
return s
|
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() {
|
func (s *Server) Dump() {
|
||||||
fmt.Printf(" Theme: %s\n", s.theme)
|
fmt.Printf(" Theme: %s\n", s.theme)
|
||||||
fmt.Printf(" Templates: %s\n", s.templates)
|
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 {
|
func New(address string, path string, auth auth.Authenticator) *Server {
|
||||||
s := Server{
|
s := Server{
|
||||||
router: mux.NewRouter(),
|
router: mux.NewRouter(),
|
||||||
auth: auth,
|
auth: auth,
|
||||||
address: address,
|
address: address,
|
||||||
fs: http.FileSystem(http.Dir(path)),
|
fs: http.FileSystem(http.Dir(path)),
|
||||||
templates: "/templates",
|
templates: "/templates",
|
||||||
theme: "/static/css/default.css",
|
templateFuncs: builtinFuncMap,
|
||||||
|
theme: "/static/css/default.css",
|
||||||
|
meta: make(map[string]string),
|
||||||
}
|
}
|
||||||
return &s
|
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