package handlers import ( "database/sql" "encoding/json" "fmt" "log" "net/http" "strings" "time" ) type FinalizedSummary struct { Pickup []string `json:"pickup"` Kitchen []string `json:"kitchen"` } type App struct { DB *sql.DB Broker *Broker FinalizeUpdate chan struct{} // notify scheduler to reload time LastSummary *FinalizedSummary } func NewApp(db *sql.DB, broker *Broker, finalizeUpdate chan struct{}) *App { return &App{ DB: db, Broker: broker, FinalizeUpdate: finalizeUpdate, } } func (app *App) RequireLevel(maxAllowed int) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { username, err := usernameFromJWT(r) if err != nil || username == "" { http.Error(w, "unauthorized", http.StatusUnauthorized) return } role, err := app.getUserRole(username) if err != nil { http.Error(w, "db error", http.StatusInternalServerError) return } if role > maxAllowed { http.Error(w, "forbidden", http.StatusForbidden) return } next.ServeHTTP(w, r) }) } } func (app *App) getUserRole(username string) (int, error) { var role int err := app.DB.QueryRow("SELECT role FROM users WHERE username = ?", username).Scan(&role) return role, err } func finalizeOrders(app *App) error { rows, err := app.DB.Query("SELECT id, username, soup, main, side FROM orders WHERE status = 'active'") if err != nil { return err } defer rows.Close() var summary []Order for rows.Next() { var o Order if err := rows.Scan(&o.ID, &o.Username, &o.Soup, &o.Main, &o.Side); err == nil { summary = append(summary, o) } } // Step 2: send summary (log, email, or message) sendSummary(app, summary) // Step 3: archive _, err = app.DB.Exec("UPDATE orders SET status = 'history' WHERE status = 'active'") // Step 4: broadcast deletions to SSE clients for _, o := range summary { msg := map[string]any{"id": o.ID, "status": "history", "event": "deleted"} if data, err := json.Marshal(msg); err == nil { app.Broker.broadcast <- data } time.Sleep(20 * time.Millisecond) } return err } func sendSummary(app *App, orders []Order) *FinalizedSummary { // Pickup view userMap := make(map[string][]string) for _, o := range orders { items := []string{} if o.Soup != "" { items = append(items, o.Soup) } items = append(items, o.Main, o.Side) userMap[o.Username] = append(userMap[o.Username], items...) } pickup := []string{} for user, items := range userMap { pickup = append(pickup, fmt.Sprintf("%s: [%s]", user, strings.Join(items, ", "))) } // Kitchen view kitchenMap := make(map[string]int) for _, o := range orders { if o.Soup != "" { kitchenMap[o.Soup]++ } kitchenMap[o.Main]++ kitchenMap[o.Side]++ } kitchen := []string{} for item, count := range kitchenMap { kitchen = append(kitchen, fmt.Sprintf("%s: %d", item, count)) } summary := &FinalizedSummary{Pickup: pickup, Kitchen: kitchen} app.LastSummary = summary // Log log.Println("=== Pickup view ===") for _, line := range pickup { log.Println(line) } log.Println("=== Kitchen view ===") for _, line := range kitchen { log.Println(line) } return summary } func (app *App) getSetting(key, def string) string { var v string err := app.DB.QueryRow("SELECT value FROM settings WHERE key = ?", key).Scan(&v) if err != nil || v == "" { return def } return v }