add new templates and template helper functions, render webring on homepage
This commit is contained in:
parent
4c3811bc87
commit
2b761b31c3
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<body>
|
||||
<header>
|
||||
<h1>Webring</h1>
|
||||
{{template "nav" .}}
|
||||
</header>
|
||||
<main>
|
||||
{{template "main" .}}
|
||||
|
|
|
@ -2,5 +2,13 @@
|
|||
|
||||
{{define "main"}}
|
||||
<h2>Latest Websites</h2>
|
||||
{{ if .SiteEntries }}
|
||||
<ul>
|
||||
{{ range .SiteEntries }}
|
||||
<li><a href="{{.Url}}">{{.Name}}</a> (<a href="/sites/view?id={{.Id}}">info</a>)</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ else }}
|
||||
<p>There's nothing to see here yet!</p>
|
||||
{{ end }}
|
||||
{{end}}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{{define "title"}}Site Entry #{{.SiteEntry.Id}}{{end}}
|
||||
{{define "main"}}
|
||||
<div class='snippet'>
|
||||
<div class='metadata'>
|
||||
<strong>{{.SiteEntry.Name}}</strong>
|
||||
<span>#{{.SiteEntry.Id}}</span>
|
||||
</div>
|
||||
<div class='metadata'>
|
||||
<time>Created: {{.SiteEntry.DateAdded}}</time>
|
||||
<p>Webmaster: {{.Webmaster.Name}}</p>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
|
@ -0,0 +1,5 @@
|
|||
{{define "nav"}}
|
||||
<nav>
|
||||
<a href="/">Home</a>
|
||||
</nav>
|
||||
{{end}}
|
Loading…
Reference in New Issue