// 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 tickets WHERE user_id = ? 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) }