Refactor Store into SessionStore; move domain SQL onto User/Question/Answer.

This commit is contained in:
2026-08-22 02:40:51 -07:00
parent f31f352838
commit c77298411e
15 changed files with 696 additions and 876 deletions
+26 -17
View File
@@ -3,6 +3,7 @@ package web
import (
"context"
"crypto/rand"
"database/sql"
"encoding/hex"
"fmt"
"html/template"
@@ -30,7 +31,7 @@ type Config struct {
}
type Server struct {
store store.DB
db *sql.DB
sessions *scs.SessionManager
tmpl *template.Template
cfg Config
@@ -84,7 +85,7 @@ type voteCtx struct {
Question store.RankedQuestion
}
func New(st store.DB, sessionStore scs.Store, templateFS fs.FS, staticFS fs.FS, cfg Config) (*Server, error) {
func New(db *sql.DB, sessionStore scs.Store, templateFS fs.FS, staticFS fs.FS, cfg Config) (*Server, error) {
if cfg.Blob == nil {
cfg.Blob = blob.Disabled{}
}
@@ -124,7 +125,7 @@ func New(st store.DB, sessionStore scs.Store, templateFS fs.FS, staticFS fs.FS,
}
return &Server{
store: st,
db: db,
sessions: sessions,
tmpl: tmpl,
cfg: cfg,
@@ -180,7 +181,7 @@ func (s *Server) withUser(next http.Handler) http.Handler {
}
id := s.sessions.GetString(r.Context(), "user_id")
if id != "" {
u, err := s.store.UserByID(r.Context(), id)
u, err := store.UserByID(r.Context(), s.db, id)
if err == nil {
r = r.WithContext(context.WithValue(r.Context(), userKey, u))
}
@@ -258,7 +259,7 @@ func (s *Server) renderHunt(w http.ResponseWriter, r *http.Request, date string)
if u := currentUser(r); u != nil {
viewer = u.ID
}
questions, err := s.store.ListHunt(r.Context(), date, viewer)
questions, err := store.ListHunt(r.Context(), s.db, date, viewer)
if err != nil {
http.Error(w, "could not load questions", http.StatusInternalServerError)
return
@@ -318,8 +319,12 @@ func (s *Server) handleSubmit(w http.ResponseWriter, r *http.Request) {
if len(city) > 80 {
city = city[:80]
}
q, err := s.store.CreateQuestion(r.Context(), u.ID, title, body, city)
if err != nil {
q := store.NewQuestion(s.db)
q.AuthorID = u.ID
q.Title = title
q.Body = body
q.City = city
if err := q.Create(r.Context()); err != nil {
http.Error(w, "could not save question", http.StatusInternalServerError)
return
}
@@ -332,14 +337,14 @@ func (s *Server) handleQuestion(w http.ResponseWriter, r *http.Request) {
if u := currentUser(r); u != nil {
viewer = u.ID
}
q, err := s.store.GetQuestion(r.Context(), id, viewer)
q, err := store.GetQuestion(r.Context(), s.db, id, viewer)
if err != nil || (q.Hidden && !currentUser(r).Admin()) {
http.NotFound(w, r)
return
}
var ans *store.Answer
if q.Answered {
ans, _ = s.store.GetAnswer(r.Context(), q.ID)
ans, _ = store.GetAnswer(r.Context(), s.db, q.ID)
}
s.exec(w, "question", questionPage{
page: s.basePage(r, q.Title),
@@ -372,7 +377,7 @@ func (s *Server) handleVote(w http.ResponseWriter, r *http.Request) {
http.Error(w, "invalid vote", http.StatusBadRequest)
return
}
if err := s.store.Vote(r.Context(), u.ID, id, value); err != nil {
if err := store.Vote(r.Context(), s.db, u.ID, id, value); err != nil {
http.Error(w, "could not vote", http.StatusInternalServerError)
return
}
@@ -383,7 +388,7 @@ func (s *Server) handleVote(w http.ResponseWriter, r *http.Request) {
s.renderLeaderboard(w, r, date)
return
}
q, err := s.store.GetQuestion(r.Context(), id, u.ID)
q, err := store.GetQuestion(r.Context(), s.db, id, u.ID)
if err != nil {
http.Error(w, "not found", http.StatusNotFound)
return
@@ -416,7 +421,7 @@ func (s *Server) renderLeaderboard(w http.ResponseWriter, r *http.Request, date
if u := currentUser(r); u != nil {
viewer = u.ID
}
questions, err := s.store.ListHunt(r.Context(), date, viewer)
questions, err := store.ListHunt(r.Context(), s.db, date, viewer)
if err != nil {
http.Error(w, "could not load questions", http.StatusInternalServerError)
return
@@ -446,17 +451,21 @@ func (s *Server) handleAnswer(w http.ResponseWriter, r *http.Request) {
if len(body) > 12000 {
body = body[:12000]
}
if err := s.store.UpsertAnswer(r.Context(), id, u.ID, body); err != nil {
ans := store.NewAnswer(s.db)
ans.QuestionID = id
ans.AuthorID = u.ID
ans.Body = body
if err := ans.Upsert(r.Context()); err != nil {
http.Error(w, "could not save answer", http.StatusInternalServerError)
return
}
ans, err := s.store.GetAnswer(r.Context(), id)
saved, err := store.GetAnswer(r.Context(), s.db, id)
if err != nil {
http.Error(w, "could not load answer", http.StatusInternalServerError)
return
}
if isHTMX(r) {
s.exec(w, "answer", questionPage{page: s.basePage(r, ""), Answer: ans})
s.exec(w, "answer", questionPage{page: s.basePage(r, ""), Answer: saved})
return
}
http.Redirect(w, r, "/questions/"+url.PathEscape(id), http.StatusSeeOther)
@@ -472,12 +481,12 @@ func (s *Server) handleHide(w http.ResponseWriter, r *http.Request) {
return
}
id := chi.URLParam(r, "id")
q, err := s.store.GetQuestion(r.Context(), id, u.ID)
q, err := store.GetQuestion(r.Context(), s.db, id, u.ID)
if err != nil {
http.NotFound(w, r)
return
}
if err := s.store.HideQuestion(r.Context(), id); err != nil {
if err := q.Hide(r.Context()); err != nil {
http.Error(w, "could not hide", http.StatusInternalServerError)
return
}