143 lines
3.4 KiB
Go
143 lines
3.4 KiB
Go
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))
|
|
}
|