210 lines
4.2 KiB
Go
210 lines
4.2 KiB
Go
|
|
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
|
||
|
|
}
|