From d2ecf6f3be46cae2948aa7ce8740f3e39a3f04ee Mon Sep 17 00:00:00 2001 From: Samuel Johnson Date: Tue, 17 Mar 2026 12:26:14 -0400 Subject: Add search functionality --- cmd/web/handlers/blog.go | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'cmd/web/handlers/blog.go') diff --git a/cmd/web/handlers/blog.go b/cmd/web/handlers/blog.go index 472b270..51b5771 100644 --- a/cmd/web/handlers/blog.go +++ b/cmd/web/handlers/blog.go @@ -24,6 +24,7 @@ type blogContext struct { Rows []models.Post Comments []models.Comment Name string + SearchTerm string IsAuth bool PagePopulated bool Offset int @@ -315,10 +316,90 @@ func (ctx *blogContext) post(w http.ResponseWriter, r *http.Request) { return } +func (ctx *blogContext) search(w http.ResponseWriter, r *http.Request) { + ctx.Rows = []models.Post{} + ctx.IsAuth = false + ctx.PagePopulated = false + + _, err := r.Cookie("paterissa_session_token") + if err == nil { + ctx.IsAuth = true + } + + ctx.Offset, _ = strconv.Atoi(r.URL.Query().Get("offset")) + ctx.SearchTerm = r.URL.Query().Get("query") + + stmt, err := ctx.db.Prepare("SELECT p.id, u.name, p.time, p.brief FROM posts p INNER JOIN logins u ON p.user_id = u.id WHERE word_similarity($1, p.brief) > 0.1 ORDER BY word_similarity($1, p.brief) DESC LIMIT 20 OFFSET $2;") + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("Internal Error")) + ctx.err.Printf("Could not prepare statement for DB: %v\n", err) + return + } + defer stmt.Close() + + rows, err := stmt.Query(ctx.SearchTerm, strconv.Itoa(ctx.Offset)) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("Internal Error")) + ctx.err.Printf("Could not load posts from DB: %v\n", err) + return + } + defer rows.Close() + + for rows.Next() { + var p models.Post + + if err = rows.Scan(&p.Id, &p.Name, &p.Time, &p.Brief); err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("Internal Error")) + ctx.err.Printf("Could not load row: %v\n", err) + return + } + + p.FormattedTime = p.Time.Format(time.ANSIC) + + ctx.Rows = append(ctx.Rows, p) + ctx.PagePopulated = true + } + + files := []string{ + "ui/html/base.tmpl.html", + "ui/html/music_player.tmpl.html", + "ui/html/pages/index.tmpl.html", + } + + funcMap := template.FuncMap{ + "add": func(a int, b int) int { + return a + b + }, + "sub": func(a int, b int) int { + return a - b + }, + } + + compiled, err := template.New("blog").Funcs(funcMap).ParseFiles(files...) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("Internal Error")) + ctx.err.Printf("Could not parse template: %v\n", err) + return + } + + err = compiled.ExecuteTemplate(w, "base", ctx) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("Internal Error")) + ctx.err.Printf("Could not execute template: %v\n", err) + return + } +} + func (ctx *blogContext) index(w http.ResponseWriter, r *http.Request) { ctx.Rows = []models.Post{} ctx.IsAuth = false ctx.PagePopulated = false + ctx.SearchTerm = "" if r.URL.Path != "/" { http.NotFound(w, r) -- cgit v1.2.3