From a94b81f95793fb52bb0ddb5b49eda3dfb156297a Mon Sep 17 00:00:00 2001
From: Gregor Best <gbe@unobtanium.de>
Date: Sun, 11 Apr 2021 23:24:42 +0200
Subject: [PATCH] Split handlers and templates

---
 main.go             | 93 ++++-----------------------------------------
 templates/index.tpl | 25 ++++++------
 2 files changed, 18 insertions(+), 100 deletions(-)

diff --git a/main.go b/main.go
index a02a9ef..6c983c6 100644
--- a/main.go
+++ b/main.go
@@ -2,13 +2,9 @@ package main
 
 import (
 	"embed"
-	"errors"
-	"fmt"
 	"html/template"
-	"io/ioutil"
 	"log"
 	"net/http"
-	"strconv"
 
 	"github.com/jmoiron/sqlx"
 	_ "modernc.org/sqlite" // Imported for side effects: registers DB driver
@@ -16,13 +12,13 @@ import (
 
 //go:embed templates/*.tpl
 var templateFS embed.FS
-var templates = template.Must(template.ParseFS(templateFS, "templates/*.tpl"))
+var templates = template.Must(template.ParseFS(templateFS, "templates/base.tpl", "templates/index.tpl"))
 
 //go:embed static/*
 var staticFS embed.FS
 
 func httpError(w http.ResponseWriter, msg string, err error, status int) {
-	log.Println(msg)
+	log.Println(msg+":", err)
 	http.Error(w, msg+": "+err.Error(), status)
 }
 
@@ -40,88 +36,13 @@ func main() {
 
 	http.Handle("/static/", http.FileServer(http.FS(staticFS)))
 
-	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
-		log.Println("handling", r.Method, r.URL, "from", r.RemoteAddr)
-
-		if r.Method == "GET" {
-			wines, err := ListWines(r.Context(), db)
-			if err != nil {
-				httpError(w, "can't list wines", err, http.StatusInternalServerError)
-				return
-			}
-
-			w.Header().Add("content-type", "text/html")
-
-			data := struct {
-				Wines []Vino
-			}{wines}
-
-			err = templates.ExecuteTemplate(w, "index.tpl", data)
-			if err != nil {
-				log.Println("can't execute index template:", err)
-			}
-
-			return
-		}
-
-		if r.Method != "POST" {
-			httpError(w, "invalid method", errors.New(r.Method), http.StatusMethodNotAllowed)
-			return
-		}
-
-		// TODO: load/store image
-
-		name := r.FormValue("name")
-		if name == "" {
-			httpError(w, "bad name", errors.New("empty or missing"), http.StatusBadRequest)
-			return
-		}
-
-		if len(name) > 80 {
-			httpError(w, "bad name", errors.New("name too long, max length is 80"), http.StatusBadRequest)
-			return
-		}
-
-		ratingVal := r.FormValue("rating")
-
-		var rating int
-		if ratingVal != "" {
-			rating, err = strconv.Atoi(ratingVal)
-			if err != nil {
-				httpError(w, "can't convert rating", err, http.StatusBadRequest)
-				return
-			}
-		}
-
-		picFile, picHdr, err := r.FormFile("picture")
-		if err != nil {
-			httpError(w, "can't load picture file", err, http.StatusInternalServerError)
-			return
-		}
-		defer picFile.Close()
-
-		log.Println("picture", picHdr.Size, picHdr.Header.Get("Content-Type"))
-
-		picData, err := ioutil.ReadAll(picFile)
-		if err != nil {
-			httpError(w, "can't read picture file", err, http.StatusInternalServerError)
-			return
-		}
-
-		vino := Vino{
-			Name:    name,
-			Rating:  rating,
-			Picture: picData,
-		}
+	handler := Handler{
+		db: db,
+	}
 
-		err = vino.Store(r.Context(), db)
-		if err != nil {
-			httpError(w, fmt.Sprintf("can't store wine %q", vino), err, http.StatusInternalServerError)
-			return
-		}
+	http.HandleFunc("/details/", handler.details)
 
-		http.Redirect(w, r, "/", http.StatusSeeOther) // TODO: Is this the correct status?
-	})
+	http.HandleFunc("/", handler.index)
 
 	const listenAddr = ":7878"
 
diff --git a/templates/index.tpl b/templates/index.tpl
index bd53485..3996bd4 100644
--- a/templates/index.tpl
+++ b/templates/index.tpl
@@ -1,14 +1,8 @@
-<!doctype html5>
-<html>
-<head>
-	<title>In Vino Veritas</title>
-	<style type="text/css">
-	span.todo {
-		background: red;
-	}
-	</style>
-</head>
-<body>
+{{ template "base" . }}
+
+{{ define "title" }}Index{{ end }}
+
+{{ define "content" }}
 	The DB contains {{ .Wines | len }} wine(s) right now:
 
 	<form method="POST" enctype="multipart/form-data" action="/add">
@@ -23,10 +17,13 @@
 	<table>
 		<tr><th>#</th><th>Name</th><th>Rating</th></tr>
 		{{ range .Wines }}
-			<tr><td>{{ .ID }}</td><td>{{ .Name }}</td><td>{{ .Rating }}</td></tr>
+			<tr>
+				<td>{{ .ID }}</td>
+				<td><a href="/details/{{ .ID }}">{{ .Name }}</a></td>
+				<td>{{ .Rating }}</td>
+			</tr>
 		{{ end }}
 	</table>
 
 	<p>And a bit of foo.</p>
-</body>
-</html>
\ No newline at end of file
+{{ end }}
\ No newline at end of file
-- 
GitLab