70 lines
1.7 KiB
Go
70 lines
1.7 KiB
Go
// Package accountTicketHandlers
|
|
// Path: /internal/handlers/account/tickets/
|
|
// File: list.go
|
|
//
|
|
// Purpose
|
|
// List all tickets belonging to the currently authenticated user.
|
|
//
|
|
// Responsibilities
|
|
// - Validate session context
|
|
// - Query DB for tickets filtered by user_id
|
|
// - Transform rows into template-safe values
|
|
//
|
|
// TODO
|
|
// - Move SQL query into storage layer (read model)
|
|
// - Support pagination or date filtering
|
|
|
|
package accountTicketHandlers
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"synlotto-website/internal/platform/bootstrap"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/justinas/nosurf"
|
|
)
|
|
|
|
func List(c *gin.Context) {
|
|
app := c.MustGet("app").(*bootstrap.App)
|
|
sm := app.SessionManager
|
|
|
|
userIDAny := sm.Get(c.Request.Context(), sessionKeyUserID)
|
|
userID, ok := userIDAny.(int64)
|
|
if !ok || userID == 0 {
|
|
c.Redirect(http.StatusSeeOther, "/account/login")
|
|
return
|
|
}
|
|
|
|
rows, err := app.DB.QueryContext(c.Request.Context(), `
|
|
SELECT id, numbers, game, price, purchased_at, created_at
|
|
FROM my_tickets
|
|
WHERE userId = ?
|
|
ORDER BY purchased_at DESC, id DESC
|
|
`, userID)
|
|
if err != nil {
|
|
c.HTML(http.StatusInternalServerError, "account/tickets/my_tickets.html", gin.H{
|
|
"title": "My Tickets",
|
|
"err": "Could not load your tickets.",
|
|
})
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
var items []ticketRow
|
|
for rows.Next() {
|
|
var t ticketRow
|
|
if err := rows.Scan(&t.ID, &t.Numbers, &t.Game, &t.Price, &t.PurchasedAt, &t.CreatedAt); err != nil {
|
|
continue
|
|
}
|
|
items = append(items, t)
|
|
}
|
|
|
|
view := gin.H{
|
|
"title": "My Tickets",
|
|
"tickets": items,
|
|
"csrfToken": nosurf.Token(c.Request), // useful if list page has inline delete in future
|
|
}
|
|
c.HTML(http.StatusOK, "account/tickets/my_tickets.html", view)
|
|
}
|