diff --git a/core/admin.go b/core/admin.go index b910951..8af40ef 100644 --- a/core/admin.go +++ b/core/admin.go @@ -33,7 +33,7 @@ func (b *Blog) AdminRoutes(r *mux.Router) { // AdminHandler is the admin landing page. func (b *Blog) AdminHandler(w http.ResponseWriter, r *http.Request) { - render.Template(w, r, "admin/index", NewVars()) + render.Template(w, r, "admin/index", nil) } // FileTree holds information about files in the document roots. @@ -106,13 +106,13 @@ func (b *Blog) EditorHandler(w http.ResponseWriter, r *http.Request) { } } - v := NewVars(map[interface{}]interface{}{ + v := map[string]interface{}{ "File": file, "Path": fp, "Body": string(body), "FromCore": fromCore, - }) - b.RenderTemplate(w, r, "admin/editor", v) + } + render.Template(w, r, "admin/editor", v) return } @@ -165,19 +165,19 @@ func (b *Blog) editorFileList(w http.ResponseWriter, r *http.Request) { trees = append(trees, tree) } - v := NewVars(map[interface{}]interface{}{ + v := map[string]interface{}{ "FileTrees": trees, - }) - b.RenderTemplate(w, r, "admin/filelist", v) + } + render.Template(w, r, "admin/filelist", v) } // SettingsHandler lets you configure the app from the frontend. func (b *Blog) SettingsHandler(w http.ResponseWriter, r *http.Request) { - v := NewVars() - // Get the current settings. settings, _ := settings.Load() - v.Data["s"] = settings + v := map[string]interface{}{ + "s": settings, + } if r.Method == http.MethodPost { redisPort, _ := strconv.Atoi(r.FormValue("redis-port")) @@ -220,7 +220,7 @@ func (b *Blog) SettingsHandler(w http.ResponseWriter, r *http.Request) { settings.Mail.Password = form.MailPassword err := form.Validate() if err != nil { - v.Error = err + v["Error"] = err } else { // Save the settings. settings.Save() @@ -230,5 +230,5 @@ func (b *Blog) SettingsHandler(w http.ResponseWriter, r *http.Request) { return } } - b.RenderTemplate(w, r, "admin/settings", v) + render.Template(w, r, "admin/settings", v) } diff --git a/core/auth.go b/core/auth.go index 29efd4b..ba59417 100644 --- a/core/auth.go +++ b/core/auth.go @@ -9,6 +9,7 @@ import ( "github.com/kirsle/blog/core/internal/log" "github.com/kirsle/blog/core/internal/middleware/auth" "github.com/kirsle/blog/core/internal/models/users" + "github.com/kirsle/blog/core/internal/render" "github.com/kirsle/blog/core/internal/responses" "github.com/kirsle/blog/core/internal/sessions" ) @@ -40,8 +41,9 @@ func (b *Blog) Login(w http.ResponseWriter, r *http.Request, u *users.User) erro // LoginHandler shows and handles the login page. func (b *Blog) LoginHandler(w http.ResponseWriter, r *http.Request) { - vars := NewVars() - vars.Form = forms.Setup{} + vars := map[string]interface{}{ + "Form": forms.Setup{}, + } var nextURL string if r.Method == http.MethodPost { @@ -49,22 +51,22 @@ func (b *Blog) LoginHandler(w http.ResponseWriter, r *http.Request) { } else { nextURL = r.URL.Query().Get("next") } - vars.Data["NextURL"] = nextURL + vars["NextURL"] = nextURL if r.Method == http.MethodPost { form := &forms.Login{ Username: r.FormValue("username"), Password: r.FormValue("password"), } - vars.Form = form + vars["Form"] = form err := form.Validate() if err != nil { - vars.Error = err + vars["Error"] = err } else { // Test the login. user, err := users.CheckAuth(form.Username, form.Password) if err != nil { - vars.Error = errors.New("bad username or password") + vars["Error"] = errors.New("bad username or password") } else { // Login OK! responses.Flash(w, r, "Login OK!") @@ -82,7 +84,7 @@ func (b *Blog) LoginHandler(w http.ResponseWriter, r *http.Request) { } } - b.RenderTemplate(w, r, "login", vars) + render.Template(w, r, "login", vars) } // LogoutHandler logs the user out and redirects to the home page. @@ -113,13 +115,14 @@ func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) { return } - v := NewVars() form := &forms.Account{ Username: user.Username, Email: user.Email, Name: user.Name, } - v.Form = form + v := map[string]interface{}{ + "Form": form, + } if r.Method == http.MethodPost { form.Username = users.Normalize(r.FormValue("username")) @@ -172,5 +175,5 @@ func (b *Blog) AccountHandler(w http.ResponseWriter, r *http.Request) { } } - b.RenderTemplate(w, r, "account", v) + render.Template(w, r, "account", v) } diff --git a/core/blog.go b/core/blog.go index de2e5d3..1955e8d 100644 --- a/core/blog.go +++ b/core/blog.go @@ -151,7 +151,7 @@ func (b *Blog) Tagged(w http.ResponseWriter, r *http.Request) { tag, ok := params["tag"] if !ok { // They're listing all the tags. - b.RenderTemplate(w, r, "blog/tags.gohtml", NewVars()) + render.Template(w, r, "blog/tags.gohtml", nil) return } @@ -182,11 +182,11 @@ func (b *Blog) CommonIndexHandler(w http.ResponseWriter, r *http.Request, tag, p title = "Blog" } - b.RenderTemplate(w, r, "blog/index", NewVars(map[interface{}]interface{}{ + render.Template(w, r, "blog/index", map[string]interface{}{ "Title": title, "Tag": tag, "Privacy": privacy, - })) + }) } // RecentPosts gets and filters the blog entries and orders them by most recent. @@ -305,15 +305,12 @@ func (b *Blog) RenderIndex(r *http.Request, tag, privacy string) template.HTML { // Render the blog index partial. var output bytes.Buffer - v := render.Vars{ - NoLayout: true, - Data: map[interface{}]interface{}{ - "PreviousPage": previousPage, - "NextPage": nextPage, - "View": view, - }, + v := map[string]interface{}{ + "PreviousPage": previousPage, + "NextPage": nextPage, + "View": view, } - b.RenderTemplate(&output, r, "blog/index.partial", v) + render.Template(&output, r, "blog/index.partial", v) return template.HTML(output.String()) } @@ -331,14 +328,11 @@ func (b *Blog) RenderTags(r *http.Request, indexView bool) template.HTML { } var output bytes.Buffer - v := render.Vars{ - NoLayout: true, - Data: map[interface{}]interface{}{ - "IndexView": indexView, - "Tags": tags, - }, + v := map[string]interface{}{ + "IndexView": indexView, + "Tags": tags, } - b.RenderTemplate(&output, r, "blog/tags.partial", v) + render.Template(&output, r, "blog/tags.partial", v) return template.HTML(output.String()) } @@ -384,10 +378,10 @@ func (b *Blog) BlogArchive(w http.ResponseWriter, r *http.Request) { result = append(result, byMonth[label]) } - v := NewVars(map[interface{}]interface{}{ + v := map[string]interface{}{ "Archive": result, - }) - b.RenderTemplate(w, r, "blog/archive", v) + } + render.Template(w, r, "blog/archive", v) } // viewPost is the underlying implementation of the handler to view a blog @@ -408,10 +402,10 @@ func (b *Blog) viewPost(w http.ResponseWriter, r *http.Request, fragment string) } } - v := NewVars(map[interface{}]interface{}{ + v := map[string]interface{}{ "Post": post, - }) - b.RenderTemplate(w, r, "blog/entry", v) + } + render.Template(w, r, "blog/entry", v) return nil } @@ -447,19 +441,16 @@ func (b *Blog) RenderPost(r *http.Request, p *posts.Post, indexView bool, numCom rendered = template.HTML(p.Body) } - meta := render.Vars{ - NoLayout: true, - Data: map[interface{}]interface{}{ - "Post": p, - "Rendered": rendered, - "Author": author, - "IndexView": indexView, - "Snipped": snipped, - "NumComments": numComments, - }, + meta := map[string]interface{}{ + "Post": p, + "Rendered": rendered, + "Author": author, + "IndexView": indexView, + "Snipped": snipped, + "NumComments": numComments, } output := bytes.Buffer{} - err = b.RenderTemplate(&output, r, "blog/entry.partial", meta) + err = render.Template(&output, r, "blog/entry.partial", meta) if err != nil { return template.HTML(fmt.Sprintf("[template error in blog/entry.partial: %s]", err.Error())) } @@ -469,9 +460,9 @@ func (b *Blog) RenderPost(r *http.Request, p *posts.Post, indexView bool, numCom // EditBlog is the blog writing and editing page. func (b *Blog) EditBlog(w http.ResponseWriter, r *http.Request) { - v := NewVars(map[interface{}]interface{}{ + v := map[string]interface{}{ "preview": "", - }) + } var post *posts.Post // Are we editing an existing post? @@ -480,7 +471,7 @@ func (b *Blog) EditBlog(w http.ResponseWriter, r *http.Request) { if err == nil { post, err = posts.Load(id) if err != nil { - v.Error = errors.New("that post ID was not found") + v["Error"] = errors.New("that post ID was not found") post = posts.New() } } @@ -496,13 +487,13 @@ func (b *Blog) EditBlog(w http.ResponseWriter, r *http.Request) { switch r.FormValue("submit") { case "preview": if post.ContentType == string(MARKDOWN) { - v.Data["preview"] = template.HTML(markdown.RenderTrustedMarkdown(post.Body)) + v["preview"] = template.HTML(markdown.RenderTrustedMarkdown(post.Body)) } else { - v.Data["preview"] = template.HTML(post.Body) + v["preview"] = template.HTML(post.Body) } case "post": if err := post.Validate(); err != nil { - v.Error = err + v["Error"] = err } else { author, _ := auth.CurrentUser(r) post.AuthorID = author.ID @@ -510,7 +501,7 @@ func (b *Blog) EditBlog(w http.ResponseWriter, r *http.Request) { post.Updated = time.Now().UTC() err = post.Save() if err != nil { - v.Error = err + v["Error"] = err } else { responses.Flash(w, r, "Post created!") responses.Redirect(w, "/"+post.Fragment) @@ -519,16 +510,16 @@ func (b *Blog) EditBlog(w http.ResponseWriter, r *http.Request) { } } - v.Data["post"] = post - b.RenderTemplate(w, r, "blog/edit", v) + v["post"] = post + render.Template(w, r, "blog/edit", v) } // DeletePost to delete a blog entry. func (b *Blog) DeletePost(w http.ResponseWriter, r *http.Request) { var post *posts.Post - v := NewVars(map[interface{}]interface{}{ + v := map[string]interface{}{ "Post": nil, - }) + } var idStr string if r.Method == http.MethodPost { @@ -557,6 +548,6 @@ func (b *Blog) DeletePost(w http.ResponseWriter, r *http.Request) { return } - v.Data["Post"] = post - b.RenderTemplate(w, r, "blog/delete", v) + v["Post"] = post + render.Template(w, r, "blog/delete", v) } diff --git a/core/comments.go b/core/comments.go index 9d10114..f6a985b 100644 --- a/core/comments.go +++ b/core/comments.go @@ -148,7 +148,6 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) { b.BadRequest(w, r, "That method is not allowed.") return } - v := NewVars() currentUser, _ := auth.CurrentUser(r) editToken := b.GetEditToken(w, r) submit := r.FormValue("submit") @@ -205,6 +204,8 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) { session.Values["c.email"] = c.Email session.Save(r, w) + v := map[string]interface{}{} + // Previewing, deleting, or posting? switch submit { case ActionPreview, ActionDelete: @@ -216,7 +217,7 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) { c.HTML = template.HTML(markdown.RenderMarkdown(c.Body)) case ActionPost: if err := c.Validate(); err != nil { - v.Error = err + v["Error"] = err } else { // Store our edit token, if we don't have one. For example, admins // can edit others' comments but should not replace their edit token. @@ -255,25 +256,24 @@ func (b *Blog) CommentHandler(w http.ResponseWriter, r *http.Request) { } } - v.Data["Thread"] = t - v.Data["Comment"] = c - v.Data["Editing"] = c.Editing - v.Data["Deleting"] = submit == ActionDelete + v["Thread"] = t + v["Comment"] = c + v["Editing"] = c.Editing + v["Deleting"] = submit == ActionDelete - b.RenderTemplate(w, r, "comments/index.gohtml", v) + render.Template(w, r, "comments/index.gohtml", v) } // SubscriptionHandler to opt out of subscriptions. func (b *Blog) SubscriptionHandler(w http.ResponseWriter, r *http.Request) { - v := NewVars() - + var err error // POST to unsubscribe from all threads. if r.Method == http.MethodPost { email := r.FormValue("email") if email == "" { - v.Error = errors.New("email address is required to unsubscribe from comment threads") + err = errors.New("email address is required to unsubscribe from comment threads") } else if _, err := mail.ParseAddress(email); err != nil { - v.Error = errors.New("invalid email address") + err = errors.New("invalid email address") } m := comments.LoadMailingList() @@ -294,7 +294,9 @@ func (b *Blog) SubscriptionHandler(w http.ResponseWriter, r *http.Request) { return } - b.RenderTemplate(w, r, "comments/subscription.gohtml", v) + render.Template(w, r, "comments/subscription.gohtml", map[string]error{ + "Error": err, + }) } // QuickDeleteHandler allows the admin to quickly delete spam without logging in. diff --git a/core/contact.go b/core/contact.go index 11a8dcc..8c97717 100644 --- a/core/contact.go +++ b/core/contact.go @@ -12,15 +12,17 @@ import ( "github.com/kirsle/blog/core/internal/forms" "github.com/kirsle/blog/core/internal/markdown" "github.com/kirsle/blog/core/internal/models/settings" + "github.com/kirsle/blog/core/internal/render" "github.com/kirsle/blog/core/internal/responses" ) // ContactRoutes attaches the contact URL to the app. func (b *Blog) ContactRoutes(r *mux.Router) { r.HandleFunc("/contact", func(w http.ResponseWriter, r *http.Request) { - v := NewVars() - form := forms.Contact{} - v.Form = &form + form := &forms.Contact{} + v := map[string]interface{}{ + "Form": form, + } // If there is no site admin, show an error. cfg, err := settings.Load() @@ -73,6 +75,6 @@ func (b *Blog) ContactRoutes(r *mux.Router) { } } - b.RenderTemplate(w, r, "contact", v) + render.Template(w, r, "contact", v) }) } diff --git a/core/errors.go b/core/errors.go index 3219985..8984360 100644 --- a/core/errors.go +++ b/core/errors.go @@ -14,8 +14,8 @@ func (b *Blog) NotFound(w http.ResponseWriter, r *http.Request, message string) } w.WriteHeader(http.StatusNotFound) - err := b.RenderTemplate(w, r, ".errors/404", render.Vars{ - Message: message, + err := render.Template(w, r, ".errors/404", map[string]string{ + "Message": message, }) if err != nil { log.Error(err.Error()) @@ -26,8 +26,8 @@ func (b *Blog) NotFound(w http.ResponseWriter, r *http.Request, message string) // Forbidden sends an HTTP 403 Forbidden response. func (b *Blog) Forbidden(w http.ResponseWriter, r *http.Request, message string) { w.WriteHeader(http.StatusForbidden) - err := b.RenderTemplate(w, r, ".errors/403", render.Vars{ - Message: message, + err := render.Template(w, r, ".errors/403", map[string]string{ + "Message": message, }) if err != nil { log.Error(err.Error()) @@ -38,8 +38,8 @@ func (b *Blog) Forbidden(w http.ResponseWriter, r *http.Request, message string) // Error sends an HTTP 500 Internal Server Error response. func (b *Blog) Error(w http.ResponseWriter, r *http.Request, message string) { w.WriteHeader(http.StatusInternalServerError) - err := b.RenderTemplate(w, r, ".errors/500", render.Vars{ - Message: message, + err := render.Template(w, r, ".errors/500", map[string]string{ + "Message": message, }) if err != nil { log.Error(err.Error()) @@ -50,8 +50,8 @@ func (b *Blog) Error(w http.ResponseWriter, r *http.Request, message string) { // BadRequest sends an HTTP 400 Bad Request. func (b *Blog) BadRequest(w http.ResponseWriter, r *http.Request, message string) { w.WriteHeader(http.StatusBadRequest) - err := b.RenderTemplate(w, r, ".errors/400", render.Vars{ - Message: message, + err := render.Template(w, r, ".errors/400", map[string]string{ + "Message": message, }) if err != nil { log.Error(err.Error()) diff --git a/core/initial-setup.go b/core/initial-setup.go index 3ad754b..d0063f5 100644 --- a/core/initial-setup.go +++ b/core/initial-setup.go @@ -14,8 +14,9 @@ import ( // SetupHandler is the initial blog setup route. func (b *Blog) SetupHandler(w http.ResponseWriter, r *http.Request) { - vars := render.Vars{ - Form: forms.Setup{}, + form := &forms.Setup{} + vars := map[string]interface{}{ + "Form": form, } // Reject if we're already set up. @@ -26,15 +27,10 @@ func (b *Blog) SetupHandler(w http.ResponseWriter, r *http.Request) { } if r.Method == http.MethodPost { - form := forms.Setup{ - Username: r.FormValue("username"), - Password: r.FormValue("password"), - Confirm: r.FormValue("confirm"), - } - vars.Form = form + form.ParseForm(r) err := form.Validate() if err != nil { - vars.Error = err + vars["Error"] = err } else { // Save the site config. log.Info("Creating default website config file") @@ -54,7 +50,7 @@ func (b *Blog) SetupHandler(w http.ResponseWriter, r *http.Request) { err := users.Create(user) if err != nil { log.Error("Error: %v", err) - vars.Error = err + vars["Error"] = err } // All set! @@ -64,5 +60,5 @@ func (b *Blog) SetupHandler(w http.ResponseWriter, r *http.Request) { } } - b.RenderTemplate(w, r, "initial-setup", vars) + render.Template(w, r, "initial-setup", vars) } diff --git a/core/internal/forms/forms.go b/core/internal/forms/forms.go index a261e60..2e7b9ef 100644 --- a/core/internal/forms/forms.go +++ b/core/internal/forms/forms.go @@ -1,6 +1,6 @@ package forms // Form is an interface for forms that can validate themselves. -type Form interface { - Validate() error -} +// type Form interface { +// Validate() error +// } diff --git a/core/internal/forms/setup.go b/core/internal/forms/setup.go index dd76a08..18afbd1 100644 --- a/core/internal/forms/setup.go +++ b/core/internal/forms/setup.go @@ -2,6 +2,7 @@ package forms import ( "errors" + "net/http" ) // Setup is for the initial blog setup page at /initial-setup. @@ -11,6 +12,13 @@ type Setup struct { Confirm string } +// Parse form values. +func (f *Setup) ParseForm(r *http.Request) { + f.Username = r.FormValue("username") + f.Password = r.FormValue("password") + f.Confirm = r.FormValue("confirm") +} + // Validate the form. func (f Setup) Validate() error { if len(f.Username) == 0 { diff --git a/core/internal/markdown/markdown.go b/core/internal/markdown/markdown.go index aa148b9..6bb1b47 100644 --- a/core/internal/markdown/markdown.go +++ b/core/internal/markdown/markdown.go @@ -125,8 +125,10 @@ func Pygmentize(language, source string) (string, error) { cacheKey := "pygmentize:" + hash // Do we have it cached? - if cached, err := Cache.Get(cacheKey); err == nil && len(cached) > 0 { - return string(cached), nil + if Cache != nil { + if cached, err := Cache.Get(cacheKey); err == nil && len(cached) > 0 { + return string(cached), nil + } } // Defer to the `pygmentize` command @@ -150,9 +152,11 @@ func Pygmentize(language, source string) (string, error) { } result = out.String() - err := Cache.Set(cacheKey, []byte(result), 60*60*24) // cool md5's don't change - if err != nil { - log.Error("Couldn't cache Pygmentize output: %s", err) + if Cache != nil { + err := Cache.Set(cacheKey, []byte(result), 60*60*24) // cool md5's don't change + if err != nil { + log.Error("Couldn't cache Pygmentize output: %s", err) + } } return result, nil diff --git a/core/internal/render/templates.go b/core/internal/render/templates.go index 0b80619..0b7affe 100644 --- a/core/internal/render/templates.go +++ b/core/internal/render/templates.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "github.com/kirsle/blog/core/internal/forms" "github.com/kirsle/blog/core/internal/log" "github.com/kirsle/blog/core/internal/middleware" "github.com/kirsle/blog/core/internal/middleware/auth" @@ -20,12 +19,12 @@ import ( // Vars is an interface to implement by the templates to pass their own custom // variables in. It auto-loads global template variables (site name, etc.) // when the template is rendered. -type Vars struct { +type vars struct { // Global, "constant" template variables. SetupNeeded bool Title string Path string - TemplatePath string + TemplatePath string // actual template file on disk LoggedIn bool CurrentUser *users.User CSRF string @@ -34,36 +33,11 @@ type Vars struct { RequestTime time.Time RequestDuration time.Duration - // Configuration variables - NoLayout bool // don't wrap in .layout.html, just render the template - // Common template variables. Message string Flashes []string Error error - Data map[interface{}]interface{} - Form forms.Form -} - -// loadDefaults combines template variables with default, globally available vars. -func (v *Vars) loadDefaults(r *http.Request) { - // Get the site settings. - s, err := settings.Load() - if err != nil { - s = settings.Defaults() - } - - if s.Initialized == false && !strings.HasPrefix(r.URL.Path, "/initial-setup") { - v.SetupNeeded = true - } - v.Request = r - v.RequestTime = r.Context().Value(types.StartTimeKey).(time.Time) - v.Title = s.Site.Title - v.Path = r.URL.Path - - user, err := auth.CurrentUser(r) - v.CurrentUser = user - v.LoggedIn = err == nil + Data interface{} } // Template responds with an HTML template. @@ -72,9 +46,30 @@ func (v *Vars) loadDefaults(r *http.Request) { // website title and user login status), the user's session may be updated with // new CSRF token, and other such things. If you just want to render a template // without all that nonsense, use RenderPartialTemplate. -func Template(w io.Writer, r *http.Request, path string, v Vars) error { +func Template(w io.Writer, r *http.Request, path string, data interface{}) error { + isPartial := strings.Contains(path, ".partial") + + // Get the site settings. + s, err := settings.Load() + if err != nil { + s = settings.Defaults() + } + // Inject globally available variables. - v.loadDefaults(r) + v := vars{ + SetupNeeded: s.Initialized == false && !strings.HasPrefix(r.URL.Path, "/initial-setup"), + + Request: r, + RequestTime: r.Context().Value(types.StartTimeKey).(time.Time), + Title: s.Site.Title, + Path: r.URL.Path, + + Data: data, + } + + user, err := auth.CurrentUser(r) + v.CurrentUser = user + v.LoggedIn = err == nil // If this is the HTTP response, handle session-related things. if rw, ok := w.(http.ResponseWriter); ok { @@ -97,11 +92,9 @@ func Template(w io.Writer, r *http.Request, path string, v Vars) error { v.RequestDuration = time.Now().Sub(v.RequestTime) v.Editable = !strings.HasPrefix(path, "admin/") - // v interface{}, withLayout bool, functions map[string]interface{}) error { var ( layout Filepath templateName string - err error ) // Find the file path to the template. @@ -110,9 +103,10 @@ func Template(w io.Writer, r *http.Request, path string, v Vars) error { log.Error("RenderTemplate(%s): file not found", path) return err } + v.TemplatePath = filepath.URI // Get the layout template. - if !v.NoLayout { + if !isPartial { templateName = "layout" layout, err = ResolvePath(".layout") if err != nil { @@ -135,7 +129,7 @@ func Template(w io.Writer, r *http.Request, path string, v Vars) error { // Parse the template files. The layout comes first because it's the wrapper // and allows the filepath template to set the page title. var templates []string - if !v.NoLayout { + if !isPartial { templates = append(templates, layout.Absolute) } t, err = t.ParseFiles(append(templates, commentEntry.Absolute, filepath.Absolute)...) diff --git a/core/pages.go b/core/pages.go index 7bea655..7e0bbbd 100644 --- a/core/pages.go +++ b/core/pages.go @@ -41,7 +41,7 @@ func (b *Blog) PageHandler(w http.ResponseWriter, r *http.Request) { // Is it a template file? if strings.HasSuffix(filepath.URI, ".gohtml") { - b.RenderTemplate(w, r, filepath.URI, NewVars()) + render.Template(w, r, filepath.URI, nil) return } @@ -58,11 +58,11 @@ func (b *Blog) PageHandler(w http.ResponseWriter, r *http.Request) { html := markdown.RenderTrustedMarkdown(body) title, _ := markdown.TitleFromMarkdown(body) - b.RenderTemplate(w, r, ".markdown", NewVars(map[interface{}]interface{}{ + render.Template(w, r, ".markdown", map[string]interface{}{ "Title": title, "HTML": template.HTML(html), - "MarkdownFile": filepath.URI, - })) + "MarkdownPath": filepath.URI, + }) return } diff --git a/core/templates.go b/core/templates.go deleted file mode 100644 index 07d45bf..0000000 --- a/core/templates.go +++ /dev/null @@ -1,40 +0,0 @@ -package core - -import ( - "io" - "net/http" - - "github.com/kirsle/blog/core/internal/render" -) - -// NewVars initializes a Vars struct with the custom Data map initialized. -// You may pass in an initial value for this map if you want. -func NewVars(data ...map[interface{}]interface{}) render.Vars { - var value map[interface{}]interface{} - if len(data) > 0 { - value = data[0] - } else { - value = make(map[interface{}]interface{}) - } - return render.Vars{ - Data: value, - } -} - -// RenderTemplate responds with an HTML template. -// -// The vars will be massaged a bit to load the global defaults (such as the -// website title and user login status), the user's session may be updated with -// new CSRF token, and other such things. -// -// For server-rendered templates given directly to the user (i.e., in controllers), -// give it the http.ResponseWriter; for partial templates you can give it a -// bytes.Buffer to write to instead. The subtle difference is whether or not the -// template will have access to the request's session. -func (b *Blog) RenderTemplate(w io.Writer, r *http.Request, path string, vars render.Vars) error { - if r == nil { - panic("core.RenderTemplate(): the *http.Request is nil!?") - } - - return render.Template(w, r, path, vars) -} diff --git a/root/.errors/400.gohtml b/root/.errors/400.gohtml index 25842a0..34ad409 100644 --- a/root/.errors/400.gohtml +++ b/root/.errors/400.gohtml @@ -2,5 +2,5 @@ {{ define "content" }}

400 Bad Request

-{{ .Message }} +{{ .Data.Message }} {{ end }} diff --git a/root/.errors/403.gohtml b/root/.errors/403.gohtml index b9832e9..61d91f8 100644 --- a/root/.errors/403.gohtml +++ b/root/.errors/403.gohtml @@ -2,5 +2,5 @@ {{ define "content" }}

403 Forbidden

-{{ .Message }} +{{ .Data.Message }} {{ end }} diff --git a/root/.errors/404.gohtml b/root/.errors/404.gohtml index aab335c..76ad398 100644 --- a/root/.errors/404.gohtml +++ b/root/.errors/404.gohtml @@ -2,7 +2,7 @@ {{ define "content" }}

404 Not Found

-{{ .Message }} +{{ .Data.Message }} {{ if .CurrentUser.Admin }}

diff --git a/root/.errors/500.gohtml b/root/.errors/500.gohtml index 2ca412f..9dcea92 100644 --- a/root/.errors/500.gohtml +++ b/root/.errors/500.gohtml @@ -2,5 +2,5 @@ {{ define "content" }}

500 Internal Server Error

-{{ .Message }} +{{ .Data.Message }} {{ end }} diff --git a/root/.layout.gohtml b/root/.layout.gohtml index 84d1eee..4060f56 100644 --- a/root/.layout.gohtml +++ b/root/.layout.gohtml @@ -79,9 +79,9 @@ {{ template "content" . }} - {{ if and .CurrentUser.Admin .Editable }} + {{ if and .CurrentUser.Admin .Editable (ne .TemplatePath ".markdown") }}

- Admin: [edit this page] + Admin: [edit this page]

{{ end }} diff --git a/root/.markdown.gohtml b/root/.markdown.gohtml index 43a7881..99c8972 100644 --- a/root/.markdown.gohtml +++ b/root/.markdown.gohtml @@ -3,4 +3,10 @@ {{ .Data.HTML }} +{{ if and .CurrentUser.Admin .Editable }} +

+ Admin: [edit this page] +

+{{ end }} + {{ end }} diff --git a/root/contact.gohtml b/root/contact.gohtml index a1af15b..66f0d99 100644 --- a/root/contact.gohtml +++ b/root/contact.gohtml @@ -7,6 +7,9 @@ administrator.

+data={{ .Data }} + +{{ $form := .Data.Form }}
@@ -19,7 +22,7 @@ class="form-control" id="name" placeholder="Anonymous" - value="{{ .Form.Name }}"> + value="{{ $form.Name }}">
@@ -28,7 +31,7 @@ class="form-control" id="email" placeholder="(if you want a response)" - value="{{ .Form.Email }}"> + value="{{ $form.Email }}">
@@ -50,7 +53,7 @@ name="message" id="message" placeholder="Message" - required>{{ .Form.Message }} + required>{{ $form.Message }}
diff --git a/root/initial-setup.gohtml b/root/initial-setup.gohtml index 27aee3e..e2bbb5e 100644 --- a/root/initial-setup.gohtml +++ b/root/initial-setup.gohtml @@ -13,6 +13,7 @@ predictable for an attacker to guess.

+{{ $form := .Data.Form }}
@@ -22,7 +23,7 @@ class="form-control" id="setup-admin-username" placeholder="Enter username" - value="{{ .Form.Username }}"> + value="{{ $form.Username }}">