This repository has been archived by the owner on Jan 7, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
templates.go
153 lines (131 loc) · 3.94 KB
/
templates.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package render
import (
"html/template"
"io"
"net/http"
"strings"
"time"
gorilla "github.com/gorilla/sessions"
"github.com/kirsle/blog/src/log"
"github.com/kirsle/blog/src/middleware"
"github.com/kirsle/blog/src/middleware/auth"
"github.com/kirsle/blog/src/sessions"
"github.com/kirsle/blog/src/types"
"github.com/kirsle/blog/models/settings"
"github.com/kirsle/blog/models/users"
)
// 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, "constant" template variables.
SetupNeeded bool
Title string
Description string
Path string
TemplatePath string // actual template file on disk
LoggedIn bool
CurrentUser *users.User
CSRF string
Editable bool // page is editable
Request *http.Request
RequestTime time.Time
RequestDuration time.Duration
// Common template variables.
Session *gorilla.Session
Message string
Flashes []string
Error error
Data interface{}
}
// Template 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. If you just want to render a template
// without all that nonsense, use RenderPartialTemplate.
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 := 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,
Description: s.Site.Description,
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 {
rw.Header().Set("Content-Type", "text/html; encoding=UTF-8")
session := sessions.Get(r)
v.Session = session
// Flashed messages.
if flashes := session.Flashes(); len(flashes) > 0 {
for _, flash := range flashes {
_ = flash
v.Flashes = append(v.Flashes, flash.(string))
}
session.Save(r, rw)
}
// CSRF token for forms.
v.CSRF = middleware.GenerateCSRFToken(rw, r, session)
}
v.RequestDuration = time.Now().Sub(v.RequestTime)
v.Editable = !strings.HasPrefix(path, "admin/")
var (
layout Filepath
templateName string
)
// Find the file path to the template.
filepath, err := ResolvePath(path)
if err != nil {
log.Error("RenderTemplate(%s): file not found", path)
return err
}
v.TemplatePath = filepath.URI
// Get the layout template.
if !isPartial {
templateName = "layout"
layout, err = ResolvePath(".layout")
if err != nil {
log.Error("RenderTemplate(%s): layout template not found", path)
return err
}
} else {
templateName = filepath.Basename
}
// The comment entry partial.
commentEntry, err := ResolvePath("comments/entry.partial")
if err != nil {
log.Error("RenderTemplate(%s): comments/entry.partial not found")
return err
}
t := template.New(filepath.Absolute).Funcs(Funcs)
// 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 !isPartial {
templates = append(templates, layout.Absolute)
}
t, err = t.ParseFiles(append(templates, commentEntry.Absolute, filepath.Absolute)...)
if err != nil {
log.Error(err.Error())
return err
}
err = t.ExecuteTemplate(w, templateName, v)
if err != nil {
log.Error("Template parsing error: %s", err)
return err
}
return nil
}