diff --git a/handlers/common.go b/handlers/common.go index a139712..2d8270f 100644 --- a/handlers/common.go +++ b/handlers/common.go @@ -12,5 +12,5 @@ var Tmpl = template.Must(template.ParseFiles( "templates/new_ticket.html", )) -var Draws []models.Draw +var Draws []models.ThunderballResult var MyTickets []models.MyTicket diff --git a/handlers/draw_handler.go b/handlers/draw_handler.go index 766e1a4..9348e43 100644 --- a/handlers/draw_handler.go +++ b/handlers/draw_handler.go @@ -3,6 +3,7 @@ package handlers import ( "log" "net/http" + "synlotto-website/helpers" "synlotto-website/models" ) @@ -36,22 +37,22 @@ func Submit(w http.ResponseWriter, r *http.Request) { log.Println("📝 Form submission received") r.ParseForm() - draw := models.Draw{ - Date: r.FormValue("date"), + draw := models.ThunderballResult{ + DrawDate: r.FormValue("date"), Machine: r.FormValue("machine"), - Ballset: r.FormValue("ballset"), - Ball1: r.FormValue("ball1"), - Ball2: r.FormValue("ball2"), - Ball3: r.FormValue("ball3"), - Ball4: r.FormValue("ball4"), - Ball5: r.FormValue("ball5"), - Thunderball: r.FormValue("thunderball"), + Ballset: helpers.Atoi(r.FormValue("ballset")), + Ball1: helpers.Atoi(r.FormValue("ball1")), + Ball2: helpers.Atoi(r.FormValue("ball2")), + Ball3: helpers.Atoi(r.FormValue("ball3")), + Ball4: helpers.Atoi(r.FormValue("ball4")), + Ball5: helpers.Atoi(r.FormValue("ball5")), + Thunderball: helpers.Atoi(r.FormValue("thunderball")), } Draws = append(Draws, draw) - log.Printf("📅 %s | 🛠 %s | 🎱 %s | 🔢 %s,%s,%s,%s,%s | ⚡ %s\n", - draw.Date, draw.Machine, draw.Ballset, + log.Printf("📅 %s | 🛠 %s | 🎱 %d | 🔢 %d,%d,%d,%d,%d | ⚡ %d\n", + draw.DrawDate, draw.Machine, draw.Ballset, draw.Ball1, draw.Ball2, draw.Ball3, draw.Ball4, draw.Ball5, draw.Thunderball) http.Redirect(w, r, "/", http.StatusSeeOther) diff --git a/handlers/ticket_handler.go b/handlers/ticket_handler.go index 18e53e6..e23cfc3 100644 --- a/handlers/ticket_handler.go +++ b/handlers/ticket_handler.go @@ -1,44 +1,50 @@ package handlers import ( + "database/sql" "log" "net/http" + "synlotto-website/helpers" "synlotto-website/models" + "synlotto-website/storage" ) -func NewTicket(w http.ResponseWriter, r *http.Request) { - log.Println("🎟️ New ticket form opened") +func NewTicket(db *sql.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + log.Println("➡️ New ticket form opened") - err := Tmpl.ExecuteTemplate(w, "new_ticket", map[string]interface{}{ - "Page": "new_ticket", - "Data": nil, - }) - if err != nil { - log.Println("❌ Template error:", err) - http.Error(w, "Error rendering ticket form", http.StatusInternalServerError) + err := Tmpl.ExecuteTemplate(w, "new_ticket", map[string]interface{}{ + "Page": "new_ticket", + "Data": nil, + }) + if err != nil { + log.Println("❌ Template error:", err) + http.Error(w, "Error rendering form", http.StatusInternalServerError) + } } } -func SubmitTicket(w http.ResponseWriter, r *http.Request) { - r.ParseForm() +func SubmitTicket(db *sql.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ticket := models.MyTicket{ + GameType: r.FormValue("game_type"), + DrawDate: r.FormValue("draw_date"), + Ball1: helpers.Atoi(r.FormValue("ball1")), + Ball2: helpers.Atoi(r.FormValue("ball2")), + Ball3: helpers.Atoi(r.FormValue("ball3")), + Ball4: helpers.Atoi(r.FormValue("ball4")), + Ball5: helpers.Atoi(r.FormValue("ball5")), + Bonus1: helpers.Nullable(helpers.Atoi(r.FormValue("bonus1"))), + Bonus2: helpers.Nullable(helpers.Atoi(r.FormValue("bonus2"))), + } - ticket := models.MyTicket{ - DrawDate: r.FormValue("draw_date"), - Ball1: r.FormValue("ball1"), - Ball2: r.FormValue("ball2"), - Ball3: r.FormValue("ball3"), - Ball4: r.FormValue("ball4"), - Ball5: r.FormValue("ball5"), - Thunderball: r.FormValue("thunderball"), + if err := storage.InsertTicket(db, ticket); err != nil { + log.Println("❌ Failed to insert ticket:", err) + http.Error(w, "Error storing ticket", http.StatusInternalServerError) + return + } + + http.Redirect(w, r, "/", http.StatusSeeOther) } - - MyTickets = append(MyTickets, ticket) - - log.Printf("🎟 Ticket for %s: %s %s %s %s %s + %s", - ticket.DrawDate, - ticket.Ball1, ticket.Ball2, ticket.Ball3, ticket.Ball4, ticket.Ball5, ticket.Thunderball, - ) - - http.Redirect(w, r, "/", http.StatusSeeOther) } diff --git a/helpers/strconv.go b/helpers/strconv.go new file mode 100644 index 0000000..bf3d8b2 --- /dev/null +++ b/helpers/strconv.go @@ -0,0 +1,8 @@ +package helpers + +import "strconv" + +func Atoi(s string) int { + n, _ := strconv.Atoi(s) + return n +} diff --git a/main.go b/main.go index 4114b2d..220179d 100644 --- a/main.go +++ b/main.go @@ -4,9 +4,12 @@ import ( "log" "net/http" "synlotto-website/handlers" + "synlotto-website/storage" ) func main() { + db := storage.InitDB("synlotto.db") + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { case "/": @@ -16,14 +19,14 @@ func main() { case "/submit": handlers.Submit(w, r) case "/ticket": - handlers.NewTicket(w, r) + handlers.NewTicket(db) case "/submit-ticket": - handlers.SubmitTicket(w, r) + handlers.SubmitTicket(db) default: http.NotFound(w, r) } }) - log.Println("🚀 Lotto Tracker running on http://localhost:8080") + log.Println("🌐 Running on http://localhost:8080") log.Fatal(http.ListenAndServe(":8080", nil)) } diff --git a/models/draw.go b/models/draw.go index 8d5b7d6..c845c39 100644 --- a/models/draw.go +++ b/models/draw.go @@ -4,7 +4,7 @@ type ThunderballResult struct { Id int DrawDate string Machine string - Ballset string + Ballset int Ball1 int Ball2 int Ball3 int diff --git a/models/myticket.go b/models/myticket.go index b3faeb9..e3d01fd 100644 --- a/models/myticket.go +++ b/models/myticket.go @@ -9,6 +9,6 @@ type MyTicket struct { Ball3 int Ball4 int Ball5 int - Bonus1 *int // Optional (nil if not used) - Bonus2 *int // For games like EuroMillions + Bonus1 *int + Bonus2 *int } diff --git a/storage/insert.go b/storage/insert.go index a3efe31..a2ccc33 100644 --- a/storage/insert.go +++ b/storage/insert.go @@ -4,6 +4,7 @@ import ( "database/sql" "log" "strings" + "synlotto-website/helpers" "synlotto-website/models" ) @@ -28,21 +29,64 @@ func InsertThunderballResult(db *sql.DB, res models.ThunderballResult) error { return err } -func InsertMyTicket(db *sql.DB, ticket models.MyTicket) error { - stmt := ` +func InsertTicket(db *sql.DB, ticket models.MyTicket) error { + // Convert optional fields to interface{} using manual check + var bonus1Val interface{} + var bonus2Val interface{} + + if ticket.Bonus1 != nil { + bonus1Val = helpers.Nullable(*ticket.Bonus1) + } else { + bonus1Val = nil + } + + if ticket.Bonus2 != nil { + bonus2Val = helpers.Nullable(*ticket.Bonus2) + } else { + bonus2Val = nil + } + + query := ` + SELECT COUNT(*) FROM my_tickets + WHERE game_type = ? AND draw_date = ? + AND ball1 = ? AND ball2 = ? AND ball3 = ? + AND ball4 = ? AND ball5 = ? AND bonus1 IS ? AND bonus2 IS ?;` + + var count int + err := db.QueryRow(query, + ticket.GameType, + ticket.DrawDate, + ticket.Ball1, + ticket.Ball2, + ticket.Ball3, + ticket.Ball4, + ticket.Ball5, + bonus1Val, + bonus2Val, + ).Scan(&count) + + isDuplicate := count > 0 + + insert := ` INSERT INTO my_tickets ( game_type, draw_date, ball1, ball2, ball3, ball4, ball5, - bonus1, bonus2 - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);` + bonus1, bonus2, duplicate + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);` - _, err := db.Exec(stmt, + _, err = db.Exec(insert, ticket.GameType, ticket.DrawDate, - ticket.Ball1, ticket.Ball2, ticket.Ball3, ticket.Ball4, ticket.Ball5, - ticket.Bonus1, ticket.Bonus2, + ticket.Ball1, ticket.Ball2, ticket.Ball3, + ticket.Ball4, ticket.Ball5, + bonus1Val, bonus2Val, + isDuplicate, ) + if err != nil { - log.Println("❌ InsertMyTicket error:", err) + log.Println("❌ Failed to insert ticket:", err) + } else if isDuplicate { + log.Println("⚠️ Duplicate ticket detected and flagged.") } + return err } diff --git a/synlotto.db b/synlotto.db new file mode 100644 index 0000000..a51eaf6 Binary files /dev/null and b/synlotto.db differ