2017-10-31 16:42:15 +00:00
|
|
|
package core
|
|
|
|
|
|
|
|
import (
|
|
|
|
"html/template"
|
|
|
|
"net/http"
|
2017-11-08 03:48:22 +00:00
|
|
|
"strings"
|
2017-11-27 03:44:36 +00:00
|
|
|
"time"
|
2017-11-07 17:01:02 +00:00
|
|
|
|
|
|
|
"github.com/kirsle/blog/core/forms"
|
2017-11-08 03:48:22 +00:00
|
|
|
"github.com/kirsle/blog/core/models/settings"
|
2017-11-07 17:53:02 +00:00
|
|
|
"github.com/kirsle/blog/core/models/users"
|
2017-10-31 16:42:15 +00:00
|
|
|
)
|
|
|
|
|
2017-11-07 17:01:02 +00:00
|
|
|
// 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 {
|
|
|
|
// Global template variables.
|
2017-11-08 03:48:22 +00:00
|
|
|
SetupNeeded bool
|
2017-11-07 17:53:02 +00:00
|
|
|
Title string
|
2017-11-08 03:48:22 +00:00
|
|
|
Path string
|
2017-11-07 17:53:02 +00:00
|
|
|
LoggedIn bool
|
|
|
|
CurrentUser *users.User
|
2017-11-24 19:56:32 +00:00
|
|
|
CSRF string
|
|
|
|
Request *http.Request
|
2017-10-31 16:42:15 +00:00
|
|
|
|
2017-11-07 17:01:02 +00:00
|
|
|
// Common template variables.
|
|
|
|
Message string
|
2017-11-20 05:49:19 +00:00
|
|
|
Flashes []string
|
2017-11-07 17:01:02 +00:00
|
|
|
Error error
|
2017-11-15 14:55:15 +00:00
|
|
|
Data map[interface{}]interface{}
|
2017-11-07 17:01:02 +00:00
|
|
|
Form forms.Form
|
|
|
|
}
|
|
|
|
|
2017-11-15 14:55:15 +00:00
|
|
|
// 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{}) *Vars {
|
|
|
|
var value map[interface{}]interface{}
|
|
|
|
if len(data) > 0 {
|
|
|
|
value = data[0]
|
|
|
|
} else {
|
|
|
|
value = make(map[interface{}]interface{})
|
|
|
|
}
|
|
|
|
return &Vars{
|
|
|
|
Data: value,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-07 17:01:02 +00:00
|
|
|
// LoadDefaults combines template variables with default, globally available vars.
|
2017-11-20 05:49:19 +00:00
|
|
|
func (v *Vars) LoadDefaults(b *Blog, w http.ResponseWriter, r *http.Request) {
|
2017-11-08 03:48:22 +00:00
|
|
|
// Get the site settings.
|
|
|
|
s, err := settings.Load()
|
|
|
|
if err != nil {
|
|
|
|
s = settings.Defaults()
|
|
|
|
}
|
|
|
|
|
2017-11-15 14:55:15 +00:00
|
|
|
if s.Initialized == false && !strings.HasPrefix(r.URL.Path, "/initial-setup") {
|
2017-11-08 03:48:22 +00:00
|
|
|
v.SetupNeeded = true
|
|
|
|
}
|
2017-11-24 19:56:32 +00:00
|
|
|
v.Request = r
|
2017-11-08 03:48:22 +00:00
|
|
|
v.Title = s.Site.Title
|
|
|
|
v.Path = r.URL.Path
|
2017-11-07 17:53:02 +00:00
|
|
|
|
2017-11-24 20:53:13 +00:00
|
|
|
user, err := b.CurrentUser(r)
|
|
|
|
v.CurrentUser = user
|
|
|
|
v.LoggedIn = err == nil
|
|
|
|
|
2017-11-20 05:49:19 +00:00
|
|
|
// Add any flashed messages from the endpoint controllers.
|
|
|
|
session := b.Session(r)
|
|
|
|
if flashes := session.Flashes(); len(flashes) > 0 {
|
|
|
|
for _, flash := range flashes {
|
|
|
|
_ = flash
|
|
|
|
v.Flashes = append(v.Flashes, flash.(string))
|
|
|
|
}
|
|
|
|
session.Save(r, w)
|
|
|
|
}
|
|
|
|
|
2017-11-24 19:56:32 +00:00
|
|
|
v.CSRF = b.GenerateCSRFToken(w, r, session)
|
2017-11-07 17:01:02 +00:00
|
|
|
}
|
2017-10-31 16:42:15 +00:00
|
|
|
|
2017-11-07 17:01:02 +00:00
|
|
|
// TemplateVars is an interface that describes the template variable struct.
|
|
|
|
type TemplateVars interface {
|
2017-11-20 05:49:19 +00:00
|
|
|
LoadDefaults(*Blog, http.ResponseWriter, *http.Request)
|
2017-10-31 16:42:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// RenderTemplate responds with an HTML template.
|
2017-11-07 17:01:02 +00:00
|
|
|
func (b *Blog) RenderTemplate(w http.ResponseWriter, r *http.Request, path string, vars TemplateVars) error {
|
2017-10-31 16:42:15 +00:00
|
|
|
// Get the layout template.
|
|
|
|
layout, err := b.ResolvePath(".layout")
|
|
|
|
if err != nil {
|
|
|
|
log.Error("RenderTemplate(%s): layout template not found", path)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// And the template in question.
|
|
|
|
filepath, err := b.ResolvePath(path)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("RenderTemplate(%s): file not found", path)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-11-26 23:53:10 +00:00
|
|
|
// The comment entry partial.
|
|
|
|
commentEntry, err := b.ResolvePath("comments/entry.partial")
|
|
|
|
if err != nil {
|
|
|
|
log.Error("RenderTemplate(%s): comments/entry.partial not found")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-11-20 05:49:19 +00:00
|
|
|
// Useful template functions.
|
|
|
|
t := template.New(filepath.Absolute).Funcs(template.FuncMap{
|
|
|
|
"StringsJoin": strings.Join,
|
2017-11-27 03:44:36 +00:00
|
|
|
"Now": time.Now,
|
2017-11-24 19:56:32 +00:00
|
|
|
"RenderPost": b.RenderPost,
|
2017-11-26 23:53:10 +00:00
|
|
|
"RenderComments": func(subject string, ids ...string) template.HTML {
|
|
|
|
session := b.Session(r)
|
|
|
|
csrf := b.GenerateCSRFToken(w, r, session)
|
|
|
|
return b.RenderComments(session, csrf, r.URL.Path, subject, ids...)
|
|
|
|
},
|
2017-11-20 05:49:19 +00:00
|
|
|
})
|
|
|
|
|
2017-10-31 16:42:15 +00:00
|
|
|
// Parse the template files. The layout comes first because it's the wrapper
|
|
|
|
// and allows the filepath template to set the page title.
|
2017-11-26 23:53:10 +00:00
|
|
|
t, err = t.ParseFiles(layout.Absolute, commentEntry.Absolute, filepath.Absolute)
|
2017-10-31 16:42:15 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Error(err.Error())
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Inject globally available variables.
|
2017-11-07 17:01:02 +00:00
|
|
|
if vars == nil {
|
|
|
|
vars = &Vars{}
|
|
|
|
}
|
2017-11-20 05:49:19 +00:00
|
|
|
vars.LoadDefaults(b, w, r)
|
2017-10-31 16:42:15 +00:00
|
|
|
|
|
|
|
w.Header().Set("Content-Type", "text/html; encoding=UTF-8")
|
|
|
|
err = t.ExecuteTemplate(w, "layout", vars)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Template parsing error: %s", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Debug("Parsed template")
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|