package main import ( "database/sql" "html/template" "log" "net/http" "time" _ "github.com/mattn/go-sqlite3" ) type Birthday struct { ID int `db:"id"` Name string `db:"name"` Birthday time.Time `db:"birthday"` GiftPurchased bool `db:"gift_purchased"` DaysUntil int `db:"days_until"` } var db *sql.DB func initDB() { var err error db, err = sql.Open("sqlite3", "./birthdays.db") if err != nil { log.Fatal(err) } // Create table if it doesn't exist createTableSQL := ` CREATE TABLE IF NOT EXISTS birthdays ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, birthday DATE NOT NULL, gift_purchased BOOLEAN DEFAULT FALSE );` _, err = db.Exec(createTableSQL) if err != nil { log.Fatal(err) } } func getBirthdays() ([]Birthday, error) { rows, err := db.Query("SELECT id, name, birthday, gift_purchased FROM birthdays ORDER BY birthday") if err != nil { return nil, err } defer rows.Close() var birthdays []Birthday for rows.Next() { var b Birthday err := rows.Scan(&b.ID, &b.Name, &b.Birthday, &b.GiftPurchased) if err != nil { return nil, err } birthdays = append(birthdays, b) } return birthdays, nil } func addBirthday(name string, birthday time.Time, giftPurchased bool) error { _, err := db.Exec("INSERT INTO birthdays (name, birthday, gift_purchased) VALUES (?, ?, ?)", name, birthday, giftPurchased) return err } func homeHandler(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { name := r.FormValue("name") birthdayStr := r.FormValue("birthday") giftPurchased := r.FormValue("giftPurchased") == "on" // Parse the birthday date birthday, err := time.Parse("2006-01-02", birthdayStr) if err != nil { log.Printf("Error parsing birthday: %v", err) http.Error(w, "Invalid birthday date", http.StatusBadRequest) return } err = addBirthday(name, birthday, giftPurchased) if err != nil { log.Printf("Error adding birthday: %v", err) http.Error(w, "Error adding birthday", http.StatusInternalServerError) return } // Redirect to avoid resubmission http.Redirect(w, r, "/", http.StatusSeeOther) return } birthdays, err := getBirthdays() if err != nil { log.Printf("Error getting birthdays: %v", err) http.Error(w, "Error getting birthdays", http.StatusInternalServerError) return } // Calculate days until each birthday for i, b := range birthdays { nextBirthday := time.Date(time.Now().Year(), b.Birthday.Month(), b.Birthday.Day(), 0, 0, 0, 0, time.Now().Location()) if nextBirthday.Before(time.Now()) { nextBirthday = nextBirthday.AddDate(1, 0, 0) } daysUntil := int(nextBirthday.Sub(time.Now()).Hours() / 24) birthdays[i].DaysUntil = daysUntil } data := struct { UpcomingBirthdays []Birthday }{ UpcomingBirthdays: birthdays, } // Parse template from template directory tmpl, err := template.ParseFiles("template/index.html") if err != nil { log.Printf("Error parsing template: %v", err) http.Error(w, "Template error", http.StatusInternalServerError) return } err = tmpl.Execute(w, data) if err != nil { log.Printf("Error executing template: %v", err) http.Error(w, "Template execution error", http.StatusInternalServerError) return } } func main() { initDB() defer db.Close() http.HandleFunc("/", homeHandler) log.Println("Server starting on http://localhost:8080") log.Fatal(http.ListenAndServe(":8080", nil)) }