// Package accountMessageHandler // Path: /internal/handlers/account/messages // File: read.go // ToDo: Remove SQL package accountMessageHandler import ( "bytes" "database/sql" "net/http" "strconv" templateHandlers "synlotto-website/internal/handlers/template" templateHelpers "synlotto-website/internal/helpers/template" errors "synlotto-website/internal/http/error" "synlotto-website/internal/logging" "synlotto-website/internal/platform/bootstrap" "github.com/gin-gonic/gin" "github.com/justinas/nosurf" ) // GET /account/messages // Renders: web/templates/account/messages/index.html func (h *AccountMessageHandlers) List(c *gin.Context) { app := c.MustGet("app").(*bootstrap.App) sm := app.SessionManager userID := mustUserID(c) // --- Pagination --- page := 1 if ps := c.Query("page"); ps != "" { if n, err := strconv.Atoi(ps); err == nil && n > 0 { page = n } } pageSize := 20 totalPages, totalCount, err := templateHelpers.GetTotalPages( c.Request.Context(), app.DB, "user_messages", "recipientId = ? AND is_archived = FALSE", []any{userID}, pageSize, ) if err != nil { logging.Info("❌ count inbox error: %v", err) c.String(http.StatusInternalServerError, "Failed to load messages") return } if page > totalPages { page = totalPages } // --- Data --- msgsAll, err := h.Svc.ListInbox(userID) if err != nil { logging.Info("❌ list inbox error: %v", err) c.String(http.StatusInternalServerError, "Failed to load messages") return } // Temporary in-memory slice (until LIMIT/OFFSET is added) start := (page - 1) * pageSize if start > len(msgsAll) { start = len(msgsAll) } end := start + pageSize if end > len(msgsAll) { end = len(msgsAll) } msgs := msgsAll[start:end] // --- Template context --- data := templateHandlers.BuildTemplateData(app, c.Writer, c.Request) ctx := templateHelpers.TemplateContext(c.Writer, c.Request, data) if f := sm.PopString(c.Request.Context(), "flash"); f != "" { ctx["Flash"] = f } ctx["CSRFToken"] = nosurf.Token(c.Request) ctx["Title"] = "Messages" ctx["Messages"] = msgs ctx["CurrentPage"] = page ctx["TotalPages"] = totalPages ctx["TotalCount"] = totalCount ctx["PageRange"] = templateHelpers.MakePageRange(1, totalPages) // --- Render --- tmpl := templateHelpers.LoadTemplateFiles("layout.html", "web/templates/account/messages/index.html") var buf bytes.Buffer if err := tmpl.ExecuteTemplate(&buf, "layout", ctx); err != nil { logging.Info("❌ Template render error: %v", err) c.String(http.StatusInternalServerError, "Error rendering messages page") return } c.Data(http.StatusOK, "text/html; charset=utf-8", buf.Bytes()) } // GET /account/messages/read?id=123 // Renders: web/templates/account/messages/read.html func (h *AccountMessageHandlers) ReadGet(c *gin.Context) { app := c.MustGet("app").(*bootstrap.App) sm := app.SessionManager userID := mustUserID(c) idStr := c.Query("id") id, err := strconv.ParseInt(idStr, 10, 64) if err != nil || id <= 0 { errors.RenderStatus(c, sm, http.StatusNotFound) return } msg, err := h.Svc.GetByID(userID, id) if err != nil || msg == nil { errors.RenderStatus(c, sm, http.StatusNotFound) return } data := templateHandlers.BuildTemplateData(app, c.Writer, c.Request) ctx := templateHelpers.TemplateContext(c.Writer, c.Request, data) ctx["CSRFToken"] = nosurf.Token(c.Request) ctx["Title"] = msg.Subject ctx["Message"] = msg tmpl := templateHelpers.LoadTemplateFiles("layout.html", "web/templates/account/messages/read.html") var buf bytes.Buffer if err := tmpl.ExecuteTemplate(&buf, "layout", ctx); err != nil { logging.Info("❌ Template render error: %v", err) c.String(http.StatusInternalServerError, "Error rendering message") return } c.Data(http.StatusOK, "text/html; charset=utf-8", buf.Bytes()) } func (h *AccountMessageHandlers) MarkReadPost(c *gin.Context) { app := c.MustGet("app").(*bootstrap.App) sm := app.SessionManager userID := mustUserID(c) idStr := c.PostForm("id") id, err := strconv.ParseInt(idStr, 10, 64) if err != nil || id <= 0 { sm.Put(c.Request.Context(), "flash", "Invalid message id.") c.Redirect(http.StatusSeeOther, c.Request.Referer()) // back to where they came from return } if err := h.Svc.MarkRead(userID, id); err != nil { logging.Info("❌ MarkRead error: %v", err) if err == sql.ErrNoRows { sm.Put(c.Request.Context(), "flash", "Message not found or not permitted.") } else { sm.Put(c.Request.Context(), "flash", "Could not mark message as read.") } c.Redirect(http.StatusSeeOther, "/account/messages") return } sm.Put(c.Request.Context(), "flash", "Message marked as read.") // Redirect back to referer when possible so UX is smooth. if ref := c.Request.Referer(); ref != "" { c.Redirect(http.StatusSeeOther, ref) } else { c.Redirect(http.StatusSeeOther, "/account/messages") } }