-
+ {{ range .Guestbooks }}
+
- {{ with .SiteUrl }}{{ . }}{{ else }}Untitled{{ end }} + {{ else }} +
No Guestbooks yet
+ {{ end }} +diff --git a/cmd/web/handlers.go b/cmd/web/handlers.go index 22cddac..bf3d2f1 100644 --- a/cmd/web/handlers.go +++ b/cmd/web/handlers.go @@ -161,10 +161,15 @@ func (app *application) getUser(w http.ResponseWriter, r *http.Request) { func (app *application) getGuestbookCreate(w http.ResponseWriter, r* http.Request) { data := app.newTemplateData(r) + if r.Header.Get("HX-Request") == "true" { + app.renderHTMX(w, r, http.StatusOK, "guestbookcreate.part.html", data) + return + } app.render(w, r, http.StatusOK, "guestbookcreate.view.tmpl.html", data) } func (app *application) postGuestbookCreate(w http.ResponseWriter, r* http.Request) { + userId := app.sessionManager.GetInt64(r.Context(), "authenticatedUserId") err := r.ParseForm() if err != nil { app.serverError(w, r, err) @@ -172,23 +177,29 @@ func (app *application) postGuestbookCreate(w http.ResponseWriter, r* http.Reque } siteUrl := r.Form.Get("siteurl") shortId := app.createShortId() - _, err = app.guestbooks.Insert(shortId, siteUrl, 0) + _, err = app.guestbooks.Insert(shortId, siteUrl, userId) if err != nil { app.serverError(w, r, err) return } app.sessionManager.Put(r.Context(), "flash", "Guestbook successfully created!") + if r.Header.Get("HX-Request") == "true" { + w.Header().Add("HX-Trigger", "newGuestbook") + data := app.newTemplateData(r) + app.renderHTMX(w, r, http.StatusOK, "guestbookcreatebutton.part.html", data) + return + } http.Redirect(w, r, fmt.Sprintf("/guestbooks/%s", shortIdToSlug(shortId)), http.StatusSeeOther) } func (app *application) getGuestbookList(w http.ResponseWriter, r *http.Request) { userId := app.sessionManager.GetInt64(r.Context(), "authenticatedUserId") - guestbooks, err := app.guestbooks.GetAll(userId) + user, err := app.users.GetById(userId) if err != nil { app.serverError(w, r, err) return } - user, err := app.users.GetById(userId) + guestbooks, err := app.guestbooks.GetAll(userId) if err != nil { app.serverError(w, r, err) return @@ -196,6 +207,10 @@ func (app *application) getGuestbookList(w http.ResponseWriter, r *http.Request) data := app.newTemplateData(r) data.Guestbooks = guestbooks data.User = user + if r.Header.Get("HX-Request") == "true" { + app.renderHTMX(w, r, http.StatusCreated, "guestbooklist.part.html", data) + return + } app.render(w, r, http.StatusOK, "guestbooklist.view.tmpl.html", data) } @@ -312,3 +327,9 @@ func (app *application) postGuestbookCommentCreate(w http.ResponseWriter, r *htt app.sessionManager.Put(r.Context(), "flash", "Comment successfully posted!") http.Redirect(w, r, fmt.Sprintf("/guestbooks/%s", guestbookSlug), http.StatusSeeOther) } + +func (app *application) deleteGuestbookComment(w http.ResponseWriter, r *http.Request) { + // slug := r.PathValue("id") + // shortId := slugToShortId(slug) + // app.guestbookComments.Delete(shortId) +} diff --git a/cmd/web/helpers.go b/cmd/web/helpers.go index 3795b8f..ee17b06 100644 --- a/cmd/web/helpers.go +++ b/cmd/web/helpers.go @@ -8,6 +8,7 @@ import ( "strconv" "time" + "git.32bit.cafe/32bitcafe/guestbook/internal/models" "github.com/gorilla/schema" ) @@ -25,6 +26,21 @@ func (app *application) clientError(w http.ResponseWriter, status int) { http.Error(w, http.StatusText(status), status) } +func (app *application) renderHTMX(w http.ResponseWriter, r *http.Request, status int, page string, data templateData) { + ts, ok := app.templateCacheHTMX[page] + if !ok { + err := fmt.Errorf("the template %s does not exist", page) + app.serverError(w, r, err) + return + } + + w.WriteHeader(status) + err := ts.Execute(w, data) + if err != nil { + app.serverError(w, r, err) + } +} + func (app *application) render(w http.ResponseWriter, r *http.Request, status int, page string, data templateData) { ts, ok := app.templateCache[page] if !ok { @@ -97,3 +113,14 @@ func (app *application) isAuthenticated(r *http.Request) bool { } return isAuthenticated } + +func (app *application) getCurrentUser(r *http.Request) *models.User { + if !app.isAuthenticated(r) { + return nil + } + user, ok := r.Context().Value(userNameContextKey).(models.User) + if !ok { + return nil + } + return &user +} diff --git a/cmd/web/main.go b/cmd/web/main.go index 63e7c2a..0269abe 100644 --- a/cmd/web/main.go +++ b/cmd/web/main.go @@ -21,6 +21,7 @@ type application struct { sequence uint16 logger *slog.Logger templateCache map[string]*template.Template + templateCacheHTMX map[string]*template.Template guestbooks *models.GuestbookModel users *models.UserModel guestbookComments *models.GuestbookCommentModel @@ -48,6 +49,12 @@ func main() { os.Exit(1) } + templateCacheHTMX, err := newHTMXTemplateCache() + if err != nil { + logger.Error(err.Error()) + os.Exit(1) + } + sessionManager := scs.New() sessionManager.Store = sqlite3store.New(db) sessionManager.Lifetime = 12 * time.Hour @@ -58,6 +65,7 @@ func main() { app := &application{ sequence: 0, templateCache: templateCache, + templateCacheHTMX: templateCacheHTMX, logger: logger, sessionManager: sessionManager, guestbooks: &models.GuestbookModel{DB: db}, diff --git a/cmd/web/middleware.go b/cmd/web/middleware.go index e539bdb..cb43934 100644 --- a/cmd/web/middleware.go +++ b/cmd/web/middleware.go @@ -79,8 +79,14 @@ func (app *application) authenticate(next http.Handler) http.Handler { app.serverError(w, r, err) return } + user, err := app.users.GetById(id) + if err != nil { + app.serverError(w, r, err) + return + } if exists { ctx := context.WithValue(r.Context(), isAuthenticatedContextKey, true) + ctx = context.WithValue(ctx, userNameContextKey, user) r = r.WithContext(ctx) } next.ServeHTTP(w, r) diff --git a/cmd/web/templates.go b/cmd/web/templates.go index 17d3a17..0eb75bb 100644 --- a/cmd/web/templates.go +++ b/cmd/web/templates.go @@ -22,6 +22,7 @@ type templateData struct { Form any IsAuthenticated bool CSRFToken string + CurrentUser *models.User } func humanDate(t time.Time) string { @@ -34,6 +35,23 @@ var functions = template.FuncMap { "slugToShortId": slugToShortId, } +func newHTMXTemplateCache() (map[string]*template.Template, error) { + cache := map[string]*template.Template{} + pages, err := filepath.Glob("./ui/html/htmx/*.part.html") + if err != nil { + return nil, err + } + for _, page := range pages { + name := filepath.Base(page) + ts, err := template.New(name).Funcs(functions).ParseFiles(page) + if err != nil { + return nil, err + } + cache[name] = ts + } + return cache, nil +} + func newTemplateCache() (map[string]*template.Template, error) { cache := map[string]*template.Template{} pages, err := filepath.Glob("./ui/html/pages/*.tmpl.html") @@ -65,5 +83,6 @@ func (app *application) newTemplateData(r *http.Request) templateData { Flash: app.sessionManager.PopString(r.Context(), "flash"), IsAuthenticated: app.isAuthenticated(r), CSRFToken: nosurf.Token(r), + CurrentUser: app.getCurrentUser(r), } } diff --git a/db/create-tables-sqlite.sql b/db/create-tables-sqlite.sql index e072cf7..499e068 100644 --- a/db/create-tables-sqlite.sql +++ b/db/create-tables-sqlite.sql @@ -13,7 +13,7 @@ CREATE TABLE guestbooks ( Id integer primary key autoincrement, ShortId integer UNIQUE NOT NULL, SiteUrl varchar(512) NOT NULL, - UserId blob(16) NOT NULL, + UserId integer NOT NULL, Created datetime NOT NULL, IsDeleted boolean NOT NULL DEFAULT FALSE, IsActive boolean NOT NULL DEFAULT TRUE, @@ -25,8 +25,8 @@ CREATE TABLE guestbooks ( CREATE TABLE guestbook_comments ( Id integer primary key autoincrement, ShortId integer UNIQUE NOT NULL, - GuestbookId blob(16) NOT NULL, - ParentId blob(16), + GuestbookId integer NOT NULL, + ParentId integer, AuthorName varchar(256) NOT NULL, AuthorEmail varchar(256) NOT NULL, AuthorSite varchar(256), diff --git a/ui/html/base.tmpl.html b/ui/html/base.tmpl.html index ef7a74c..1a88342 100644 --- a/ui/html/base.tmpl.html +++ b/ui/html/base.tmpl.html @@ -2,14 +2,15 @@
-No Guestbooks yet
+ {{ end }} +