mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-18 01:57:02 +00:00
Added partial templates
mailbox/list now renders
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/jhillyerd/inbucket"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
Session *sessions.Session
|
||||
Vars map[string]string
|
||||
Session *sessions.Session
|
||||
DataStore *inbucket.DataStore
|
||||
}
|
||||
|
||||
func (c *Context) Close() {
|
||||
@@ -14,9 +18,13 @@ func (c *Context) Close() {
|
||||
}
|
||||
|
||||
func NewContext(req *http.Request) (*Context, error) {
|
||||
vars := mux.Vars(req)
|
||||
sess, err := sessionStore.Get(req, "inbucket")
|
||||
ds := inbucket.NewDataStore()
|
||||
ctx := &Context{
|
||||
Session: sess,
|
||||
Vars: vars,
|
||||
Session: sess,
|
||||
DataStore: ds,
|
||||
}
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
|
||||
@@ -8,21 +8,8 @@ import (
|
||||
)
|
||||
|
||||
var TemplateFuncs = template.FuncMap{
|
||||
// Reversable routing function
|
||||
"reverse": func(name string, things ...interface{}) string {
|
||||
// Convert the things to strings
|
||||
strs := make([]string, len(things))
|
||||
for i, th := range things {
|
||||
strs[i] = fmt.Sprint(th)
|
||||
}
|
||||
// Grab the route
|
||||
u, err := Router.Get(name).URL(strs...)
|
||||
if err != nil {
|
||||
inbucket.Error("Failed to reverse route: %v", err)
|
||||
return "/ROUTE-ERROR"
|
||||
}
|
||||
return u.Path
|
||||
},
|
||||
// Reversable routing function (shared with templates)
|
||||
"reverse": reverse,
|
||||
// Friendly date & time rendering
|
||||
"friendlyTime": func(t time.Time) template.HTML {
|
||||
ty, tm, td := t.Date()
|
||||
@@ -33,3 +20,18 @@ var TemplateFuncs = template.FuncMap{
|
||||
return template.HTML(t.Format("Mon Jan 2, 2006"))
|
||||
},
|
||||
}
|
||||
|
||||
func reverse(name string, things ...interface{}) string {
|
||||
// Convert the things to strings
|
||||
strs := make([]string, len(things))
|
||||
for i, th := range things {
|
||||
strs[i] = fmt.Sprint(th)
|
||||
}
|
||||
// Grab the route
|
||||
u, err := Router.Get(name).URL(strs...)
|
||||
if err != nil {
|
||||
inbucket.Error("Failed to reverse route: %v", err)
|
||||
return "/ROUTE-ERROR"
|
||||
}
|
||||
return u.Path
|
||||
}
|
||||
|
||||
@@ -1,52 +1,52 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/jhillyerd/inbucket/app/inbucket"
|
||||
"github.com/robfig/revel"
|
||||
"html/template"
|
||||
"github.com/jhillyerd/inbucket"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Mailbox struct {
|
||||
*rev.Controller
|
||||
}
|
||||
|
||||
func (c Mailbox) Index(name string) rev.Result {
|
||||
c.Validation.Required(name).Message("Account name is required")
|
||||
|
||||
if c.Validation.HasErrors() {
|
||||
c.Validation.Keep()
|
||||
c.FlashParams()
|
||||
return c.Redirect(Application.Index)
|
||||
func MailboxIndex(w http.ResponseWriter, req *http.Request, ctx *Context) (err error) {
|
||||
name := req.FormValue("name")
|
||||
if len(name) == 0 {
|
||||
ctx.Session.AddFlash("Account name is required", "errors")
|
||||
http.Redirect(w, req, reverse("RootIndex"), http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
|
||||
return c.Render(name)
|
||||
return RenderTemplate("mailbox/index.html", w, map[string]interface{}{
|
||||
"ctx": ctx,
|
||||
"name": name,
|
||||
})
|
||||
}
|
||||
|
||||
func (c Mailbox) List(name string) rev.Result {
|
||||
c.Validation.Required(name).Message("Account name is required")
|
||||
|
||||
if c.Validation.HasErrors() {
|
||||
c.Validation.Keep()
|
||||
c.FlashParams()
|
||||
return c.Redirect(Application.Index)
|
||||
func MailboxList(w http.ResponseWriter, req *http.Request, ctx *Context) (err error) {
|
||||
name := ctx.Vars["name"]
|
||||
if len(name) == 0 {
|
||||
ctx.Session.AddFlash("Account name is required", "errors")
|
||||
http.Redirect(w, req, reverse("RootIndex"), http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
|
||||
ds := inbucket.NewDataStore()
|
||||
mb, err := ds.MailboxFor(name)
|
||||
mb, err := ctx.DataStore.MailboxFor(name)
|
||||
if err != nil {
|
||||
return c.RenderError(err)
|
||||
return err
|
||||
}
|
||||
messages, err := mb.GetMessages()
|
||||
if err != nil {
|
||||
return c.RenderError(err)
|
||||
return err
|
||||
}
|
||||
rev.INFO.Printf("Got %v messsages", len(messages))
|
||||
inbucket.Trace("Got %v messsages", len(messages))
|
||||
|
||||
c.Response.Out.Header().Set("Expires", "-1")
|
||||
return c.Render(name, messages)
|
||||
return RenderPartial("mailbox/_list.html", w, map[string]interface{}{
|
||||
"ctx": ctx,
|
||||
"name": name,
|
||||
"messages": messages,
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
func (c Mailbox) Show(name string, id string) rev.Result {
|
||||
func MailboxShow(w http.ResponseWriter, req *http.Request, ctx *Context) (err error) {
|
||||
c.Validation.Required(name).Message("Account name is required")
|
||||
c.Validation.Required(id).Message("Message ID is required")
|
||||
|
||||
@@ -77,6 +77,7 @@ func (c Mailbox) Show(name string, id string) rev.Result {
|
||||
}
|
||||
|
||||
func (c Mailbox) Delete(name string, id string) rev.Result {
|
||||
func MailboxDelete(w http.ResponseWriter, req *http.Request, ctx *Context) (err error) {
|
||||
c.Validation.Required(name).Message("Account name is required")
|
||||
c.Validation.Required(id).Message("Message ID is required")
|
||||
|
||||
@@ -104,6 +105,7 @@ func (c Mailbox) Delete(name string, id string) rev.Result {
|
||||
}
|
||||
|
||||
func (c Mailbox) Html(name string, id string) rev.Result {
|
||||
func MailboxHtml(w http.ResponseWriter, req *http.Request, ctx *Context) (err error) {
|
||||
c.Validation.Required(name).Message("Account name is required")
|
||||
c.Validation.Required(id).Message("Message ID is required")
|
||||
|
||||
@@ -135,6 +137,7 @@ func (c Mailbox) Html(name string, id string) rev.Result {
|
||||
}
|
||||
|
||||
func (c Mailbox) Source(name string, id string) rev.Result {
|
||||
func MailboxSource(w http.ResponseWriter, req *http.Request, ctx *Context) (err error) {
|
||||
c.Validation.Required(name).Message("Account name is required")
|
||||
c.Validation.Required(id).Message("Message ID is required")
|
||||
|
||||
@@ -161,3 +164,4 @@ func (c Mailbox) Source(name string, id string) rev.Result {
|
||||
c.Response.Out.Header().Set("Expires", "-1")
|
||||
return c.RenderText(*raw)
|
||||
}
|
||||
*/
|
||||
@@ -5,5 +5,7 @@ import (
|
||||
)
|
||||
|
||||
func RootIndex(w http.ResponseWriter, req *http.Request, ctx *Context) (err error) {
|
||||
return T("root-index.html").Execute(w, nil)
|
||||
return RenderTemplate("root/index.html", w, map[string]interface{}{
|
||||
"ctx": ctx,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -31,17 +31,19 @@ var Router *mux.Router
|
||||
var sessionStore sessions.Store
|
||||
|
||||
func setupRoutes(cfg inbucket.WebConfig) {
|
||||
r := mux.NewRouter()
|
||||
Router = r
|
||||
Router = mux.NewRouter()
|
||||
inbucket.Info("Theme templates mapped to '%v'", cfg.TemplateDir)
|
||||
inbucket.Info("Theme static content mapped to '%v'", cfg.PublicDir)
|
||||
|
||||
r := Router
|
||||
// Static content
|
||||
r.PathPrefix("/public/").Handler(http.StripPrefix("/public/",
|
||||
http.FileServer(http.Dir(cfg.PublicDir))))
|
||||
|
||||
// Root
|
||||
r.Path("/").Handler(handler(RootIndex))
|
||||
r.Path("/").Handler(handler(RootIndex)).Name("RootIndex").Methods("GET")
|
||||
r.Path("/mailbox").Handler(handler(MailboxIndex)).Name("MailboxIndex").Methods("GET")
|
||||
r.Path("/mailbox/list/{name}").Handler(handler(MailboxList)).Name("MailboxList").Methods("GET")
|
||||
}
|
||||
|
||||
// Start() the web server
|
||||
|
||||
@@ -3,31 +3,81 @@ package web
|
||||
import (
|
||||
"github.com/jhillyerd/inbucket"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var cachedTemplates = map[string]*template.Template{}
|
||||
var cachedMutex sync.Mutex
|
||||
var cachedTemplates = map[string]*template.Template{}
|
||||
var cachedPartials = map[string]*template.Template{}
|
||||
|
||||
func T(name string) *template.Template {
|
||||
// RenderTemplate fetches the named template and renders it to the provided
|
||||
// ResponseWriter.
|
||||
func RenderTemplate(name string, w http.ResponseWriter, data interface{}) error {
|
||||
t, err := ParseTemplate(name, false)
|
||||
if err != nil {
|
||||
inbucket.Error("Error in template '%v': %v", name, err)
|
||||
return err
|
||||
}
|
||||
w.Header().Set("Expires", "-1")
|
||||
return t.Execute(w, data)
|
||||
}
|
||||
|
||||
// RenderPartial fetches the named template and renders it to the provided
|
||||
// ResponseWriter.
|
||||
func RenderPartial(name string, w http.ResponseWriter, data interface{}) error {
|
||||
t, err := ParseTemplate(name, true)
|
||||
if err != nil {
|
||||
inbucket.Error("Error in template '%v': %v", name, err)
|
||||
return err
|
||||
}
|
||||
w.Header().Set("Expires", "-1")
|
||||
return t.Execute(w, data)
|
||||
}
|
||||
|
||||
// ParseTemplate loads the requested template along with _base.html, caching
|
||||
// the result (if configured to do so)
|
||||
func ParseTemplate(name string, partial bool) (*template.Template, error) {
|
||||
cachedMutex.Lock()
|
||||
defer cachedMutex.Unlock()
|
||||
|
||||
if t, ok := cachedTemplates[name]; ok {
|
||||
return t
|
||||
return t, nil
|
||||
}
|
||||
|
||||
templateDir := inbucket.GetWebConfig().TemplateDir
|
||||
templateFile := filepath.Join(templateDir, name)
|
||||
inbucket.Trace("Parsing template %v", templateFile)
|
||||
cfg := inbucket.GetWebConfig()
|
||||
tempPath := strings.Replace(name, "/", string(filepath.Separator), -1)
|
||||
tempFile := filepath.Join(cfg.TemplateDir, tempPath)
|
||||
inbucket.Trace("Parsing template %v", tempFile)
|
||||
|
||||
t := template.New("_base.html").Funcs(TemplateFuncs)
|
||||
t = template.Must(t.ParseFiles(
|
||||
filepath.Join(templateDir, "_base.html"),
|
||||
templateFile,
|
||||
))
|
||||
cachedTemplates[name] = t
|
||||
var err error
|
||||
var t *template.Template
|
||||
if partial {
|
||||
// Need to get basename of file to make it root template w/ funcs
|
||||
base := path.Base(name)
|
||||
t = template.New(base).Funcs(TemplateFuncs)
|
||||
t, err = t.ParseFiles(tempFile)
|
||||
} else {
|
||||
t = template.New("_base.html").Funcs(TemplateFuncs)
|
||||
t, err = t.ParseFiles(filepath.Join(cfg.TemplateDir, "_base.html"), tempFile)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return t
|
||||
// Allows us to disable caching for theme development
|
||||
if cfg.TemplateCache {
|
||||
if partial {
|
||||
inbucket.Trace("Caching partial %v", name)
|
||||
cachedTemplates[name] = t
|
||||
} else {
|
||||
inbucket.Trace("Caching template %v", name)
|
||||
cachedTemplates[name] = t
|
||||
}
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user