diff options
Diffstat (limited to 'page')
| -rw-r--r-- | page/page.go | 58 | ||||
| -rw-r--r-- | page/render.go | 137 |
2 files changed, 160 insertions, 35 deletions
diff --git a/page/page.go b/page/page.go index b2cc3e1..adb2362 100644 --- a/page/page.go +++ b/page/page.go @@ -46,11 +46,11 @@ import ( // The exported fields can be filled in the yaml at the top of a page and // utilized within. type Page struct { - path string - Title string - Description string - AuthorName string - AuthorEmail string + path string + DefaultTitle string `yaml:"title"` + DefaultDescription string `yaml:"description"` + AuthorName string + AuthorEmail string // Tags to apply to the page in question. Useful for Index() Tags map[string]interface{} Date *PageTime @@ -76,8 +76,14 @@ var CacheIndex = true // backend. var FileSystem = os.DirFS(".") +// TemplateDirectory is the parent directory which templates are stored, +// usually the BaseTemplate is stored here as well, though it does not +// have to be. Currently this is used for the 4xx and 5xx pages. ( 4xx.md +// and 5xx.md respectively. +var TemplateDirectory = "tpl" + // BaseTemplate can be adjusted to change the base template used in rendering. -var BaseTemplate = "inc/base.html" +var BaseTemplate = "tpl/base.md" // Suffix is applied to all pages for reading off of the disk. var Suffix = ".md" @@ -107,6 +113,46 @@ func (p Page) Path() string { return filepath.ToSlash(p.path) } +// Title returns `DefaultTitle` unless `.Vars.Title` is +// set, then it returns that instead. +func (p Page) Title() string { + if p.Vars == nil { + return p.DefaultTitle + } + + t, ok := p.Vars["Title"] + if !ok { + return p.DefaultTitle + } + + nt, ok := t.(string) + if !ok { + return p.DefaultTitle + } + + return nt +} + +// Description returns `DefaultDescription` unless `.Vars.Description` is +// set, then it returns that instead. +func (p Page) Description() string { + if p.Vars == nil { + return p.DefaultDescription + } + + t, ok := p.Vars["Description"] + if !ok { + return p.DefaultDescription + } + + nt, ok := t.(string) + if !ok { + return p.DefaultDescription + } + + return nt +} + // Global is specifically for use inside of a page markdown file or // in a base template. This simply returns the package Global variable. func (p *Page) Global() interface{} { diff --git a/page/render.go b/page/render.go index 6cbabf9..d35ba38 100644 --- a/page/render.go +++ b/page/render.go @@ -1,20 +1,104 @@ package page import ( + "bytes" "net/http" "path/filepath" "strings" ) -// Render is a lower level option, allowing you to specify local -// variables and the status code in which to return. -func Render(w http.ResponseWriter, r *http.Request, - path string, vars map[string]interface{}, statusCode int) { +func getURLPath(r *http.Request) string { u := r.URL.Path if u == "/" { u = "/index" } + return u +} + +// Render5xx is automatically called if any render fails, +// additionally you can call it for your own uses. It will +// try to use the 5xx template but will fall back to a plain +// page if that fails. +func Render5xx(w http.ResponseWriter, r *http.Request, + vars map[string]interface{}, statusCode int) { + u := getURLPath(r) + + Logger.Printf("%s %s %d %s", + r.RemoteAddr, + r.Method, + statusCode, + u) + + p := NewPage(TemplateDirectory + "/5xx") + + buf := &bytes.Buffer{} + + err := p.Render(buf) + if err != nil { + Logger.Printf("%s %s path: %s while trying 5xx: %s", + r.RemoteAddr, + r.Method, + u, + err) + http.Error(w, "Internal server error", statusCode) + + return + } + + w.WriteHeader(statusCode) + + _, _ = w.Write(buf.Bytes()) + + Logger.Printf("%s %s %d %s", r.RemoteAddr, r.Method, statusCode, u) +} + +// Render4xx is mostly used to render a 404 page, pulls from 404 template. +// automatically called by Render if a page is missing. +func Render4xx(w http.ResponseWriter, r *http.Request, + vars map[string]interface{}, statusCode int) { + u := getURLPath(r) + + Logger.Printf("%s %s %d %s", + r.RemoteAddr, + r.Method, + statusCode, + u) + + p := NewPage(TemplateDirectory + "/4xx") + + buf := &bytes.Buffer{} + + err := p.Render(buf) + if err != nil { + Logger.Printf("%s %s path: %s while trying 404: %s", + r.RemoteAddr, + r.Method, + u, + err) + Render5xx(w, r, vars, http.StatusInternalServerError) + + return + } + + w.WriteHeader(statusCode) + + _, err = w.Write(buf.Bytes()) + if err != nil { + Render5xx(w, r, nil, http.StatusInternalServerError) + + return + } + + Logger.Printf("%s %s %d %s", r.RemoteAddr, r.Method, statusCode, u) +} + +// Render is a lower level option, allowing you to specify local +// variables and the status code in which to return. +func Render(w http.ResponseWriter, r *http.Request, + path string, vars map[string]interface{}, statusCode int) { + u := getURLPath(r) + u = filepath.Join(".", u) // Sepcifically use the specified path for the page @@ -24,42 +108,37 @@ func Render(w http.ResponseWriter, r *http.Request, p.Vars = vars } - err := p.Render(w) + buf := &bytes.Buffer{} + + err := p.Render(buf) if err != nil { if strings.HasSuffix(err.Error(), "no such file or directory") { - Logger.Printf("%s %s %d %s", - r.RemoteAddr, - r.Method, - http.StatusNotFound, - u) + Render4xx(w, r, vars, http.StatusNotFound) - p = NewPage("404") - - w.WriteHeader(http.StatusNotFound) + return + } - err := p.Render(w) - if err != nil { - Logger.Printf("%s %s path: %s while trying 404: %s", - r.RemoteAddr, - r.Method, - u, - err) - http.Error(w, "Internal server error", - http.StatusInternalServerError) + Logger.Printf("%s %s path: %s rendering encountered: %s", + r.RemoteAddr, + r.Method, + u, + err) + Render5xx(w, r, vars, http.StatusInternalServerError) - return - } + return + } - return - } + w.WriteHeader(statusCode) - Logger.Printf("%s %s path: %s encountered: %s", + _, err = w.Write(buf.Bytes()) + if err != nil { + Logger.Printf("%s %s %d %s: while writing buf: %s", r.RemoteAddr, r.Method, + statusCode, u, err) - http.Error(w, "Internal server error", - http.StatusInternalServerError) + Render5xx(w, r, nil, http.StatusInternalServerError) return } |
