Fix rendering, render 404 errors, flatten redirects

This commit is contained in:
Jan-Lukas Else 2020-07-31 21:02:47 +02:00
parent 0175ce1729
commit 12c4415cd3
8 changed files with 100 additions and 42 deletions

19
errors.go Normal file
View File

@ -0,0 +1,19 @@
package main
import (
"fmt"
"net/http"
)
type errorData struct {
Title string
Message string
}
func serve404(w http.ResponseWriter, r *http.Request) {
render(w, templateError, &errorData{
Title: "404 Not Found",
Message: fmt.Sprintf("`%s` was not found", r.RequestURI),
})
w.WriteHeader(http.StatusNotFound)
}

17
http.go
View File

@ -76,10 +76,12 @@ func buildHandler() (http.Handler, error) {
} }
for _, path := range allRedirectPaths { for _, path := range allRedirectPaths {
if path != "" { if path != "" {
r.Get(path, serveRedirect) r.With(minifier.Middleware).Get(path, serveRedirect)
} }
} }
r.With(minifier.Middleware).NotFound(serve404)
return r, nil return r, nil
} }
@ -105,9 +107,12 @@ func (d *dynamicHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
func slashTrimmedPath(r *http.Request) string { func slashTrimmedPath(r *http.Request) string {
path := r.URL.Path return trimSlash(r.URL.Path)
if len(path) > 1 { }
path = strings.TrimSuffix(path, "/")
} func trimSlash(s string) string {
return path if len(s) > 1 {
s = strings.TrimSuffix(s, "/")
}
return s
} }

View File

@ -21,13 +21,13 @@ func servePost(w http.ResponseWriter, r *http.Request) {
path := slashTrimmedPath(r) path := slashTrimmedPath(r)
post, err := getPost(r.Context(), path) post, err := getPost(r.Context(), path)
if err == errPostNotFound { if err == errPostNotFound {
http.NotFound(w, r) serve404(w, r)
return return
} else if err != nil { } else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
render(w, templatePostName, post) render(w, templatePost, post)
} }
func getPost(context context.Context, path string) (*Post, error) { func getPost(context context.Context, path string) (*Post, error) {

View File

@ -10,32 +10,41 @@ import (
var errRedirectNotFound = errors.New("redirect not found") var errRedirectNotFound = errors.New("redirect not found")
func serveRedirect(w http.ResponseWriter, r *http.Request) { func serveRedirect(w http.ResponseWriter, r *http.Request) {
redirect, err := getRedirect(r.Context(), slashTrimmedPath(r)) redirect, more, err := getRedirect(r.Context(), slashTrimmedPath(r))
if err == errRedirectNotFound { if err == errRedirectNotFound {
http.NotFound(w, r) serve404(w, r)
return return
} else if err != nil { } else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
w.WriteHeader(http.StatusFound) // Flatten redirects
_ = templates.ExecuteTemplate(w, templateRedirectName, struct { if more {
for more == true {
redirect, more, _ = getRedirect(r.Context(), trimSlash(redirect))
}
}
// Send redirect
w.Header().Set("Location", redirect)
render(w, templateRedirect, struct {
Permalink string Permalink string
}{ }{
Permalink: redirect, Permalink: redirect,
}) })
w.WriteHeader(http.StatusFound)
} }
func getRedirect(context context.Context, fromPath string) (string, error) { func getRedirect(context context.Context, fromPath string) (string, bool, error) {
var toPath string var toPath string
row := appDb.QueryRowContext(context, "select toPath from redirects where fromPath=?", fromPath) var moreRedirects int
err := row.Scan(&toPath) row := appDb.QueryRowContext(context, "select toPath, (select count(*) from redirects where fromPath=(select toPath from redirects where fromPath=?)) as more from redirects where fromPath=?", fromPath, fromPath)
err := row.Scan(&toPath, &moreRedirects)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return "", errRedirectNotFound return "", false, errRedirectNotFound
} else if err != nil { } else if err != nil {
return "", err return "", false, err
} }
return toPath, nil return toPath, moreRedirects > 0, nil
} }
func allRedirectPaths() ([]string, error) { func allRedirectPaths() ([]string, error) {

View File

@ -2,18 +2,21 @@ package main
import ( import (
"bytes" "bytes"
"fmt"
"html/template" "html/template"
"log" "log"
"net/http" "net/http"
) )
const templatePostName = "post.gohtml" const templatePost = "post"
const templateRedirectName = "redirect.gohtml" const templateError = "error"
const templateRedirect = "redirect"
var templates *template.Template var templates map[string]*template.Template
var templateFunctions template.FuncMap
func initRendering() { func initRendering() {
templateFunctions := template.FuncMap{ templateFunctions = template.FuncMap{
"blog": func() *configBlog { "blog": func() *configBlog {
return appConfig.blog return appConfig.blog
}, },
@ -25,23 +28,25 @@ func initRendering() {
} }
return template.HTML(htmlContent) return template.HTML(htmlContent)
}, },
"title": func(post Post) string { "p": func(post Post, parameter string) string {
return post.Parameters["title"] return post.Parameters[parameter]
}, },
} }
var err error templates = make(map[string]*template.Template)
for _, name := range []string{templatePost, templateError, templateRedirect} {
templates, err = template.New("templates").Funcs(templateFunctions).ParseGlob("templates/*.gohtml") templates[name] = loadTemplate(name)
if err != nil {
log.Fatal(err)
} }
} }
func loadTemplate(name string) *template.Template {
return template.Must(template.New(name).Funcs(templateFunctions).ParseFiles("templates/base.gohtml", fmt.Sprintf("templates/%s.gohtml", name)))
}
func render(w http.ResponseWriter, template string, data interface{}) { func render(w http.ResponseWriter, template string, data interface{}) {
// We need to use a buffer here to enable minification // We need to use a buffer here to enable minification
var buffer bytes.Buffer var buffer bytes.Buffer
err := templates.ExecuteTemplate(&buffer, template, data) err := templates[template].ExecuteTemplate(&buffer, template, data)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
} }

14
templates/error.gohtml Normal file
View File

@ -0,0 +1,14 @@
{{ define "title" }}
<title>{{ with .Title }}{{ . }} - {{end}}{{ blog.Title }}</title>
{{ end }}
{{ define "main" }}
<main>
{{ with .Title }}<h1>{{ . }}</h1>{{ end }}
{{ with .Message }}{{ md . }}{{ end }}
</main>
{{ end }}
{{ define "error" }}
{{ template "base" . }}
{{ end }}

View File

@ -1,14 +1,18 @@
{{ template "base" . }}
{{ define "title" }} {{ define "title" }}
<title>{{ with title . }}{{ . }} - {{end}}{{ blog.Title }}</title> <title>{{ with p . "title" }}{{ . }} - {{end}}{{ blog.Title }}</title>
{{ end }} {{ end }}
{{ define "main" }} {{ define "main" }}
<main class=h-entry> <main class=h-entry>
<article> <article>
{{ with title . }}<h1 class=p-name>{{ . }}</h1>{{ end }} {{ with p . "title" }}<h1 class=p-name>{{ . }}</h1>{{ end }}
<div class=e-content>{{ md .Content }}</div> {{ with .Content }}
<div class=e-content>{{ md . }}</div>
{{ end }}
</article> </article>
</main> </main>
{{ end }}
{{ define "post"}}
{{ template "base" . }}
{{ end }} {{ end }}

View File

@ -1,7 +1,9 @@
<!doctype html> {{ define "redirect" }}
<html lang={{ blog.Lang }}> <!doctype html>
<meta charset="utf-8"/> <html lang={{ blog.Lang }}>
<meta name="robots" content="noindex"> <meta charset="utf-8"/>
<title>{{ .Permalink }}</title> <meta name="robots" content="noindex">
<link rel="canonical" href="{{ .Permalink }}"/> <title>{{ .Permalink }}</title>
<meta http-equiv="refresh" content="0; url={{ .Permalink }}"/> <link rel="canonical" href="{{ .Permalink }}"/>
<meta http-equiv="refresh" content="0; url={{ .Permalink }}"/>
{{ end }}