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 {
if path != "" {
r.Get(path, serveRedirect)
r.With(minifier.Middleware).Get(path, serveRedirect)
}
}
r.With(minifier.Middleware).NotFound(serve404)
return r, nil
}
@ -105,9 +107,12 @@ func (d *dynamicHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
func slashTrimmedPath(r *http.Request) string {
path := r.URL.Path
if len(path) > 1 {
path = strings.TrimSuffix(path, "/")
}
return path
return trimSlash(r.URL.Path)
}
func trimSlash(s string) string {
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)
post, err := getPost(r.Context(), path)
if err == errPostNotFound {
http.NotFound(w, r)
serve404(w, r)
return
} else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
render(w, templatePostName, post)
render(w, templatePost, post)
}
func getPost(context context.Context, path string) (*Post, error) {

View File

@ -10,32 +10,41 @@ import (
var errRedirectNotFound = errors.New("redirect not found")
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 {
http.NotFound(w, r)
serve404(w, r)
return
} else if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusFound)
_ = templates.ExecuteTemplate(w, templateRedirectName, struct {
// Flatten redirects
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: 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
row := appDb.QueryRowContext(context, "select toPath from redirects where fromPath=?", fromPath)
err := row.Scan(&toPath)
var moreRedirects int
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 {
return "", errRedirectNotFound
return "", false, errRedirectNotFound
} else if err != nil {
return "", err
return "", false, err
}
return toPath, nil
return toPath, moreRedirects > 0, nil
}
func allRedirectPaths() ([]string, error) {

View File

@ -2,18 +2,21 @@ package main
import (
"bytes"
"fmt"
"html/template"
"log"
"net/http"
)
const templatePostName = "post.gohtml"
const templateRedirectName = "redirect.gohtml"
const templatePost = "post"
const templateError = "error"
const templateRedirect = "redirect"
var templates *template.Template
var templates map[string]*template.Template
var templateFunctions template.FuncMap
func initRendering() {
templateFunctions := template.FuncMap{
templateFunctions = template.FuncMap{
"blog": func() *configBlog {
return appConfig.blog
},
@ -25,23 +28,25 @@ func initRendering() {
}
return template.HTML(htmlContent)
},
"title": func(post Post) string {
return post.Parameters["title"]
"p": func(post Post, parameter string) string {
return post.Parameters[parameter]
},
}
var err error
templates, err = template.New("templates").Funcs(templateFunctions).ParseGlob("templates/*.gohtml")
if err != nil {
log.Fatal(err)
templates = make(map[string]*template.Template)
for _, name := range []string{templatePost, templateError, templateRedirect} {
templates[name] = loadTemplate(name)
}
}
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{}) {
// We need to use a buffer here to enable minification
var buffer bytes.Buffer
err := templates.ExecuteTemplate(&buffer, template, data)
err := templates[template].ExecuteTemplate(&buffer, template, data)
if err != nil {
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" }}
<title>{{ with title . }}{{ . }} - {{end}}{{ blog.Title }}</title>
<title>{{ with p . "title" }}{{ . }} - {{end}}{{ blog.Title }}</title>
{{ end }}
{{ define "main" }}
<main class=h-entry>
<article>
{{ with title . }}<h1 class=p-name>{{ . }}</h1>{{ end }}
<div class=e-content>{{ md .Content }}</div>
{{ with p . "title" }}<h1 class=p-name>{{ . }}</h1>{{ end }}
{{ with .Content }}
<div class=e-content>{{ md . }}</div>
{{ end }}
</article>
</main>
{{ end }}
{{ define "post"}}
{{ template "base" . }}
{{ end }}

View File

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