From 2b761b31c3baf47faae1e83b6d08af2b3b1fbea7 Mon Sep 17 00:00:00 2001 From: yequari Date: Sat, 22 Jul 2023 01:23:47 -0700 Subject: [PATCH] add new templates and template helper functions, render webring on homepage --- cmd/web/handlers.go | 47 ++++++++++++++++----------------- cmd/web/helpers.go | 24 +++++++++++++++++ cmd/web/main.go | 12 +++++++-- cmd/web/templates.go | 48 ++++++++++++++++++++++++++++++++++ internal/models/siteentry.go | 25 +++--------------- ui/html/base.tmpl.html | 1 + ui/html/pages/home.tmpl.html | 8 ++++++ ui/html/pages/view.tmpl.html | 13 +++++++++ ui/html/partials/nav.tmpl.html | 5 ++++ 9 files changed, 136 insertions(+), 47 deletions(-) create mode 100644 cmd/web/templates.go create mode 100644 ui/html/pages/view.tmpl.html create mode 100644 ui/html/partials/nav.tmpl.html diff --git a/cmd/web/handlers.go b/cmd/web/handlers.go index e33839e..379d168 100644 --- a/cmd/web/handlers.go +++ b/cmd/web/handlers.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "net/http" - "text/template" "git.32bit.cafe/yequari/webring/internal/models" ) @@ -15,21 +14,14 @@ func (app *application) home(w http.ResponseWriter, r *http.Request) { return } - files := []string{ - "./ui/html/base.tmpl.html", - "./ui/html/pages/home.tmpl.html", - } - - ts, err := template.ParseFiles(files...) - if err != nil { - app.serverError(w, err) - return - } - - err = ts.ExecuteTemplate(w, "base", nil) + sites, err := app.siteEntries.Latest() if err != nil { app.serverError(w, err) } + + app.render(w, http.StatusOK, "home.tmpl.html", &templateData{ + SiteEntries: sites, + }) } func (app *application) webmasterView(w http.ResponseWriter, r *http.Request) { @@ -52,18 +44,12 @@ func (app *application) webmasterCreate(w http.ResponseWriter, r *http.Request) } func (app *application) siteEntryView(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/sites/view" { - entries, err := app.siteEntries.Latest() - if err != nil { - app.serverError(w, err) - return - } - for _, entry := range entries { - fmt.Fprintf(w, "%+v\n", entry) - } + id := models.SiteId(r.URL.Query().Get("id")) + + if id == "" { + app.notFound(w) return } - id := models.SiteId(r.URL.Query().Get("id")) siteEntry, err := app.siteEntries.Get(id) if err != nil { @@ -75,7 +61,20 @@ func (app *application) siteEntryView(w http.ResponseWriter, r *http.Request) { return } - fmt.Fprintf(w, "%+v", siteEntry) + webmaster, err := app.webmasters.Get(siteEntry.Webmaster) + if err != nil { + if errors.Is(err, models.ErrNoRecord) { + app.notFound(w) + } else { + app.serverError(w, err) + } + return + } + + app.render(w, http.StatusOK, "view.tmpl.html", &templateData{ + SiteEntry: siteEntry, + Webmaster: webmaster, + }) } func (app *application) siteEntryCreate(w http.ResponseWriter, r *http.Request) { diff --git a/cmd/web/helpers.go b/cmd/web/helpers.go index 505665c..25d2b22 100644 --- a/cmd/web/helpers.go +++ b/cmd/web/helpers.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "fmt" "net/http" "path" @@ -30,3 +31,26 @@ func (app *application) cleanUrl(url string) string { s = "http://" + s return s } + +func (app *application) render(w http.ResponseWriter, status int, page string, data *templateData) { + ts, ok := app.templateCache[page] + if !ok { + err := fmt.Errorf("the template %s does not exist", page) + app.serverError(w, err) + return + } + + // a buffer to attempt to write the template to + // before writing it to the ResponseWriter w + buf := new(bytes.Buffer) + + err := ts.ExecuteTemplate(buf, "base", data) + if err != nil { + app.serverError(w, err) + return + } + + w.WriteHeader(status) + + buf.WriteTo(w) +} diff --git a/cmd/web/main.go b/cmd/web/main.go index 2f8a994..a909bf7 100644 --- a/cmd/web/main.go +++ b/cmd/web/main.go @@ -1,15 +1,16 @@ package main import ( + "database/sql" "flag" "log" "net/http" "os" - "database/sql" + "text/template" "git.32bit.cafe/yequari/webring/internal/models" - _ "modernc.org/sqlite" + _ "modernc.org/sqlite" ) type application struct { @@ -17,6 +18,7 @@ type application struct { infoLog *log.Logger siteEntries *models.SiteEntryModel webmasters *models.WebmasterModel + templateCache map[string]*template.Template } func main() { @@ -33,11 +35,17 @@ func main() { } defer db.Close() + templateCache, err := newTemplateCache() + if err != nil { + errorLog.Fatal(err) + } + app := &application{ errorLog: errorLog, infoLog: infoLog, siteEntries: &models.SiteEntryModel{DB: db}, webmasters: &models.WebmasterModel{DB: db}, + templateCache: templateCache, } srv := &http.Server{ diff --git a/cmd/web/templates.go b/cmd/web/templates.go new file mode 100644 index 0000000..bac2753 --- /dev/null +++ b/cmd/web/templates.go @@ -0,0 +1,48 @@ +package main + +import ( + "path/filepath" + "text/template" + + "git.32bit.cafe/yequari/webring/internal/models" +) + +type templateData struct { + SiteEntry *models.SiteEntry + Webmaster *models.Webmaster + SiteEntries []*models.SiteEntry +} + +func newTemplateCache() (map[string]*template.Template, error) { + cache := map[string]*template.Template{} + + pages, err := filepath.Glob("./ui/html/pages/*.tmpl.html") + if err != nil { + return nil, err + } + + for _, page := range pages { + name := filepath.Base(page) + + ts, err := template.ParseFiles("./ui/html/base.tmpl.html") + if err != nil { + return nil, err + } + + // parse all partials into the template set + ts, err = ts.ParseGlob("./ui/html/partials/*.tmpl.html") + if err != nil { + return nil, err + } + + // parse the page template last + ts, err = ts.ParseFiles(page) + if err != nil { + return nil, err + } + + cache[name] = ts + } + + return cache, nil +} diff --git a/internal/models/siteentry.go b/internal/models/siteentry.go index c307e13..b74fc09 100644 --- a/internal/models/siteentry.go +++ b/internal/models/siteentry.go @@ -47,8 +47,7 @@ func (m *SiteEntryModel) Get(id SiteId) (*SiteEntry, error) { s := &SiteEntry{} - var timeStr string - err := row.Scan(&s.Id, &s.Name, &s.Url, &s.Webmaster, &timeStr, &s.Next, &s.Prev) + err := row.Scan(&s.Id, &s.Name, &s.Url, &s.Webmaster, &s.DateAdded, &s.Next, &s.Prev) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, ErrNoRecord @@ -56,13 +55,6 @@ func (m *SiteEntryModel) Get(id SiteId) (*SiteEntry, error) { return nil, err } } - // time is stored as a string in sqlite, so we need to parse it - // probably is something taken care of in the driver - dateAdded, err := time.Parse(time.DateTime, timeStr) - if err != nil { - return nil, err - } - s.DateAdded = dateAdded return s, nil } @@ -76,8 +68,7 @@ func (m *SiteEntryModel) GetByUrl(url string) (*SiteEntry, error) { s := &SiteEntry{} - var timeStr string - err := row.Scan(&s.Id, &s.Name, &s.Url, &s.Webmaster, &timeStr, &s.Next, &s.Prev) + err := row.Scan(&s.Id, &s.Name, &s.Url, &s.Webmaster, &s.DateAdded, &s.Next, &s.Prev) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, ErrNoRecord @@ -85,15 +76,8 @@ func (m *SiteEntryModel) GetByUrl(url string) (*SiteEntry, error) { return nil, err } } - // time is stored as a string in sqlite, so we need to parse it - // probably is something taken care of in the driver - s.DateAdded, err = time.Parse(time.DateTime, timeStr) - if err != nil { - return nil, err - } return s, nil - } // Update existing SiteEntry with the values of passed entry @@ -119,15 +103,14 @@ func (m *SiteEntryModel) Latest() ([]*SiteEntry, error) { defer rows.Close() entries := []*SiteEntry{} - var timeStr string + // var timeStr string for rows.Next() { s := &SiteEntry{} - err = rows.Scan(&s.Id, &s.Name, &s.Url, &s.Webmaster, &timeStr) + err = rows.Scan(&s.Id, &s.Name, &s.Url, &s.Webmaster, &s.DateAdded) if err != nil { return nil, err } - s.DateAdded, err = time.Parse(time.DateTime, timeStr) if err != nil { return nil, err } diff --git a/ui/html/base.tmpl.html b/ui/html/base.tmpl.html index 8f42e53..2957ff9 100644 --- a/ui/html/base.tmpl.html +++ b/ui/html/base.tmpl.html @@ -8,6 +8,7 @@

Webring

+ {{template "nav" .}}
{{template "main" .}} diff --git a/ui/html/pages/home.tmpl.html b/ui/html/pages/home.tmpl.html index 48c09ef..5710007 100644 --- a/ui/html/pages/home.tmpl.html +++ b/ui/html/pages/home.tmpl.html @@ -2,5 +2,13 @@ {{define "main"}}

Latest Websites

+{{ if .SiteEntries }} + +{{ else }}

There's nothing to see here yet!

+{{ end }} {{end}} diff --git a/ui/html/pages/view.tmpl.html b/ui/html/pages/view.tmpl.html new file mode 100644 index 0000000..6e83c19 --- /dev/null +++ b/ui/html/pages/view.tmpl.html @@ -0,0 +1,13 @@ +{{define "title"}}Site Entry #{{.SiteEntry.Id}}{{end}} +{{define "main"}} +
+ + +
+{{end}} diff --git a/ui/html/partials/nav.tmpl.html b/ui/html/partials/nav.tmpl.html new file mode 100644 index 0000000..83045a1 --- /dev/null +++ b/ui/html/partials/nav.tmpl.html @@ -0,0 +1,5 @@ +{{define "nav"}} + +{{end}}