Files
feedmee/backend/handlers/app.go
2025-10-16 23:50:29 +02:00

151 lines
3.4 KiB
Go

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) *App {
return &App{
DB: db,
Broker: broker,
FinalizeUpdate: make(chan struct{}, 1),
}
}
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
}