package main import ( "database/sql" "encoding/json" "fmt" "net/http" "os" "strconv" "time" "code.akitsuki.me/AkitsukiNagi/logging" _ "github.com/joho/godotenv/autoload" _ "github.com/lib/pq" ) type Event struct { Title string `json:"title"` Description string `json:"description"` Year int `json:"year"` } type Response struct { Year int `json:"year"` Month int `json:"month"` Day int `json:"day"` Events []*Event `json:"events"` } var ( db *sql.DB connStr = fmt.Sprintf( "host=%s user=%s password=%s dbname=%s port=%s sslmode=%s", os.Getenv("HOST"), os.Getenv("USER"), os.Getenv("PASSWORD"), os.Getenv("DBNAME"), os.Getenv("PORT"), os.Getenv("SSLMODE"), ) loc *time.Location port int static = http.FileServer(http.Dir("./static")) ) func init() { var err error port, err = strconv.Atoi(os.Getenv("HTTP_PORT")) if err != nil { logging.GetLogger().Critical("Error parsing port: %v", err) } } func main() { loc, _ = time.LoadLocation("Asia/Taipei") var err error db, err = sql.Open("postgres", connStr) if err != nil { logging.GetLogger().Error("Failed to connect to the database: %v", err) } err = db.Ping() if err != nil { logging.GetLogger().Error("Failed to ping to the database: %v", err) } else { logging.GetLogger().Info("Successfully connected to the database.") } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { static.ServeHTTP(w, r) }) http.Handle("/static/", http.StripPrefix("/static", static)) http.HandleFunc("/static/index.html", func(w http.ResponseWriter, r *http.Request) { http.NotFound(w, r) }) http.HandleFunc("/api/query", serveAPI) logging.GetLogger().Info("Server started on localhost:%d", port) logging.GetLogger().Error("%v", http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) } func serveAPI(w http.ResponseWriter, r *http.Request) { query := r.URL.Query() var ( resp Response events []*Event date time.Time sYear = query.Get("year") sMonth = query.Get("month") sDay = query.Get("day") ) if sYear == "" && sMonth == "" && sDay == "" { date = time.Now() events = apiQuerying(date.Year(), int(date.Month()), date.Day()) resp = Response{ Year: date.Year(), Month: int(date.Month()), Day: date.Day(), Events: events, } err := json.NewEncoder(w).Encode(resp) if err != nil { logging.GetLogger().Error("Failed to parse data into json: %v", err) } return } year, month, day := parseTime(sYear, sMonth, sDay) date = time.Now() sDate := fmt.Sprintf("%d/%d/%d", year, month, day) date, err := time.Parse("2006/1/2", sDate) if err != nil { logging.GetLogger().Error("Error parsing date: %v", err) } events = apiQuerying(date.Year(), int(date.Month()), date.Day()) resp = Response{ Year: date.Year(), Month: int(date.Month()), Day: date.Day(), Events: events, } err = json.NewEncoder(w).Encode(resp) if err != nil { logging.GetLogger().Error("Failed to parse data into json: %v", err) } } func apiQuerying(year, month, day int) []*Event { var ( rows *sql.Rows err error ) rows, err = db.Query("SELECT year, title, description FROM events WHERE month = $1 AND day = $2 AND YEAR <= $3 ORDER BY year", month, day, year) if err != nil { logging.GetLogger().Error("%v", err) } var events []*Event defer rows.Close() for rows.Next() { event := &Event{} err := rows.Scan(&event.Year, &event.Title, &event.Description) if err != nil { logging.GetLogger().Error("%v", err) } else { events = append(events, event) } } return events } func parseTime(sYear, sMonth, sDay string) (int, int, int) { var ( year int = 0 month int = 0 day int = 0 err error reset = false now = time.Now() ) if sYear != "" { year, err = strconv.Atoi(sYear) if err != nil { year = 0 } } if sYear == "" || year == 0 { reset = true } if sMonth != "" { month, err = strconv.Atoi(sMonth) if err != nil { month = 0 } } if sMonth == "" || month == 0 { reset = true } if sDay != "" { day, err = strconv.Atoi(sDay) if err != nil { day = 0 } } if sDay == "" || day == 0 { reset = true } if reset { year, month, day = now.Year(), int(now.Month()), now.Day() } return year, month, day }