diff --git a/conf/inbucket.conf b/conf/inbucket.conf index ff64374..a38e978 100644 --- a/conf/inbucket.conf +++ b/conf/inbucket.conf @@ -32,7 +32,7 @@ ip4.port=9000 theme=integral # Path to the selected themes template files -templates.dir=%(install.dir)s/themes/%(theme)s/templates +template.dir=%(install.dir)s/themes/%(theme)s/templates # Path to the selected themes public (static) files public.dir=%(install.dir)s/themes/%(theme)s/public diff --git a/config.go b/config.go index beee858..4ae451b 100644 --- a/config.go +++ b/config.go @@ -17,10 +17,10 @@ type SmtpConfig struct { } type WebConfig struct { - Ip4address net.IP - Ip4port int - TemplatesDir string - PublicDir string + Ip4address net.IP + Ip4port int + TemplateDir string + PublicDir string } var smtpConfig *SmtpConfig @@ -68,7 +68,7 @@ func LoadConfig(filename string) error { requireOption(messages, "smtp", "domain") requireOption(messages, "web", "ip4.address") requireOption(messages, "web", "ip4.port") - requireOption(messages, "web", "templates.dir") + requireOption(messages, "web", "template.dir") requireOption(messages, "web", "public.dir") requireOption(messages, "datastore", "path") if messages.Len() > 0 { @@ -151,12 +151,12 @@ func parseWebConfig() error { return fmt.Errorf("Failed to parse %v: %v", option, err) } - option = "[web]templates.dir" - str, err = Config.String("web", "templates.dir") + option = "[web]template.dir" + str, err = Config.String("web", "template.dir") if err != nil { return fmt.Errorf("Failed to parse %v: %v", option, err) } - webConfig.TemplatesDir = str + webConfig.TemplateDir = str option = "[web]public.dir" str, err = Config.String("web", "public.dir") diff --git a/themes/integral/public/images/img10.jpg b/themes/integral/public/images/img10.jpg deleted file mode 100644 index 9fe1f17..0000000 Binary files a/themes/integral/public/images/img10.jpg and /dev/null differ diff --git a/themes/integral/templates/header.html b/themes/integral/templates/_base.html similarity index 57% rename from themes/integral/templates/header.html rename to themes/integral/templates/_base.html index a483983..f1d304a 100644 --- a/themes/integral/templates/header.html +++ b/themes/integral/templates/_base.html @@ -4,19 +4,21 @@ Design by Free CSS Templates http://www.freecsstemplates.org Released for free under a Creative Commons Attribution 2.5 License --> +{{define "col1menu"}}{{/* Used inside #content div */}} +
+ +
+{{end}} -{{.title}} - +{{template "title" .}} + - -{{range .moreStyles}} - -{{end}} -{{range .moreScripts}} - -{{end}} +
+{{template "content" .}} +
+ + + diff --git a/themes/integral/templates/footer.html b/themes/integral/templates/footer.html deleted file mode 100644 index ba7a67c..0000000 --- a/themes/integral/templates/footer.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/themes/integral/templates/Application/Index.html b/themes/integral/templates/root-index.html similarity index 68% rename from themes/integral/templates/Application/Index.html rename to themes/integral/templates/root-index.html index 466ec39..f809a4a 100644 --- a/themes/integral/templates/Application/Index.html +++ b/themes/integral/templates/root-index.html @@ -1,15 +1,11 @@ -{{set "title" "Inbucket" .}} -{{template "header.html" .}} -{{template "menu.html" .}} - +{{define "title"}}Inbucket{{end}} +{{define "content"}} +{{template "col1menu" .}}
- {{template "errors.html" .}} -

Inbucket is an email testing service; it will accept email for any email address and make it available to view without a password.

To view email for a particular address, enter the username portion of the address into the box on the upper right and click go.

- -{{template "footer.html" .}} +{{end}} diff --git a/web/app.go b/web/app.go deleted file mode 100644 index 17499a5..0000000 --- a/web/app.go +++ /dev/null @@ -1,31 +0,0 @@ -package web - -import ( - "github.com/jhillyerd/inbucket/app/smtpd" - "github.com/robfig/revel" -) - -type Application struct { - *rev.Controller -} - -func (c Application) Index() rev.Result { - return c.Render() -} - -type SmtpdPlugin struct { - rev.EmptyPlugin - server *smtpd.Server -} - -func (p SmtpdPlugin) OnAppStart() { - domain := rev.Config.StringDefault("smtpd.domain", "localhost") - port := rev.Config.IntDefault("smtpd.port", 2500) - rev.INFO.Printf("SMTP Daemon plugin init {domain: %v, port: %v}", domain, port) - p.server = smtpd.New(domain, port) - go p.server.Start() -} - -func init() { - rev.RegisterPlugin(SmtpdPlugin{}) -} diff --git a/web/context.go b/web/context.go new file mode 100644 index 0000000..73aaaf7 --- /dev/null +++ b/web/context.go @@ -0,0 +1,25 @@ +package web + +import ( + "github.com/gorilla/sessions" + "net/http" +) + +type Context struct { + Session *sessions.Session +} + +func (c *Context) Close() { + // Do nothing +} + +func NewContext(req *http.Request) (*Context, error) { + sess, err := sessionStore.Get(req, "inbucket") + ctx := &Context{ + Session: sess, + } + if err != nil { + return ctx, err + } + return ctx, err +} diff --git a/web/root_controller.go b/web/root_controller.go new file mode 100644 index 0000000..7205fdf --- /dev/null +++ b/web/root_controller.go @@ -0,0 +1,9 @@ +package web + +import ( + "net/http" +) + +func RootIndex(w http.ResponseWriter, req *http.Request, ctx *Context) (err error) { + return T("root-index.html").Execute(w, nil) +} diff --git a/web/server.go b/web/server.go index 082d621..c4ac8bf 100644 --- a/web/server.go +++ b/web/server.go @@ -6,11 +6,15 @@ package web import ( "fmt" "github.com/gorilla/mux" + "github.com/gorilla/sessions" "github.com/jhillyerd/inbucket" "net/http" + "thegoods.biz/httpbuf" "time" ) +type handler func(http.ResponseWriter, *http.Request, *Context) error + /* type WebServer struct { thing string @@ -24,24 +28,31 @@ func NewWebServer() *Server { var Router *mux.Router +var sessionStore sessions.Store + func setupRoutes(cfg inbucket.WebConfig) { r := mux.NewRouter() Router = r - inbucket.Info("Theme templates mapped to '%v'", cfg.TemplatesDir) + inbucket.Info("Theme templates mapped to '%v'", cfg.TemplateDir) inbucket.Info("Theme static content mapped to '%v'", cfg.PublicDir) // Static content r.PathPrefix("/public/").Handler(http.StripPrefix("/public/", http.FileServer(http.Dir(cfg.PublicDir)))) + + // Root + r.Path("/").Handler(handler(RootIndex)) } // Start() the web server func Start() { cfg := inbucket.GetWebConfig() setupRoutes(cfg) + + sessionStore = sessions.NewCookieStore([]byte("something-very-secret")) + addr := fmt.Sprintf("%v:%v", cfg.Ip4address, cfg.Ip4port) inbucket.Info("HTTP listening on TCP4 %v", addr) - s := &http.Server{ Addr: addr, Handler: Router, @@ -54,3 +65,31 @@ func Start() { inbucket.Error("HTTP server failed: %v", err) } } + +// ServeHTTP builds the context and passes onto the real handler +func (h handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { + // Create the context + ctx, err := NewContext(req) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer ctx.Close() + + // Run the handler, grab the error, and report it + buf := new(httpbuf.Buffer) + err = h(buf, req, ctx) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Save the session + if err = ctx.Session.Save(req, buf); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Apply the buffered response to the writer + buf.Apply(w) +} diff --git a/web/template.go b/web/template.go new file mode 100644 index 0000000..121f3c9 --- /dev/null +++ b/web/template.go @@ -0,0 +1,33 @@ +package web + +import ( + "github.com/jhillyerd/inbucket" + "html/template" + "path/filepath" + "sync" +) + +var cachedTemplates = map[string]*template.Template{} +var cachedMutex sync.Mutex + +func T(name string) *template.Template { + cachedMutex.Lock() + defer cachedMutex.Unlock() + + if t, ok := cachedTemplates[name]; ok { + return t + } + + templateDir := inbucket.GetWebConfig().TemplateDir + templateFile := filepath.Join(templateDir, name) + inbucket.Trace("Parsing template %v", templateFile) + + t := template.New("_base.html").Funcs(TemplateFuncs) + t = template.Must(t.ParseFiles( + filepath.Join(templateDir, "_base.html"), + templateFile, + )) + cachedTemplates[name] = t + + return t +}