holiday-api/main.go

221 lines
6.2 KiB
Go
Raw Normal View History

2023-06-16 07:42:50 +00:00
package main
import (
"embed"
2023-06-23 17:31:02 +00:00
"github.com/gin-gonic/gin"
2023-06-20 14:10:46 +00:00
"github.com/google/uuid"
2023-06-16 07:42:50 +00:00
"github.com/joho/godotenv"
2023-06-20 14:10:46 +00:00
_ "github.com/lib/pq"
"holiday-api/holiday"
"holiday-api/migration"
"html/template"
2023-06-16 07:42:50 +00:00
"log"
"net/http"
2023-06-20 14:10:46 +00:00
"os"
"strconv"
2023-06-20 14:10:46 +00:00
"strings"
"time"
2023-06-16 07:42:50 +00:00
)
//go:embed db/dev/*.sql
var devMigrations embed.FS
2023-06-20 14:10:46 +00:00
//go:embed db/prod/*.sql
var prodMigrations embed.FS
var isDev = false
2023-06-16 07:42:50 +00:00
func init() {
godotenv.Load()
2023-06-20 14:10:46 +00:00
if strings.Contains(os.Getenv("PROFILE"), "dev") {
isDev = true
}
2023-06-16 07:42:50 +00:00
log.SetPrefix("")
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}
func main() {
client, err := connectToDb()
if err != nil {
log.Fatalf("couldn't connect to db: %v", err)
}
2023-06-20 14:10:46 +00:00
migrationFolder := prodMigrations
if isDev {
migrationFolder = devMigrations
}
if err := migration.InitializeMigrations(client, migrationFolder); err != nil {
2023-06-16 07:42:50 +00:00
log.Fatalf("couldn't execute migrations: %v", err)
}
2023-06-23 17:31:02 +00:00
g := gin.Default()
2023-06-16 07:42:50 +00:00
g.Static("assets", "assets")
2023-06-23 17:31:02 +00:00
loadTemplates(g)
2023-06-20 14:10:46 +00:00
2023-06-23 17:31:02 +00:00
holidayService := holiday.Service{DB: client}
2023-06-20 14:10:46 +00:00
2023-06-23 17:31:02 +00:00
g.GET("/api/v1/holidays", getHolidays(holidayService))
2023-06-23 17:31:02 +00:00
setupAdminDashboard(g.Group("/admin"), holidayService)
2023-06-23 17:31:02 +00:00
g.GET("/", func(c *gin.Context) {
year := time.Now().Year()
search := holiday.Search{Country: "HR", Year: &year}
if err := c.ShouldBindQuery(&search); err != nil {
2023-06-23 17:31:02 +00:00
c.AbortWithError(http.StatusBadRequest, err)
return
}
holidays, _ := holidayService.Find(search, holiday.Paging{PageSize: 100})
c.HTML(http.StatusOK, "index.gohtml", gin.H{"Search": search, "Holidays": mapHolidays(holidays).Holidays})
})
g.GET("/documentation", func(c *gin.Context) {
c.HTML(http.StatusOK, "documentation.gohtml", nil)
})
g.GET("/search", func(c *gin.Context) {
2023-06-23 17:31:02 +00:00
request := holiday.Search{}
if err := c.ShouldBindQuery(&request); err != nil {
c.AbortWithError(http.StatusBadRequest, err)
return
}
2023-06-23 17:31:02 +00:00
search := holiday.Search{Country: request.Country, Date: request.Date}
holidays, _ := holidayService.Find(search, holiday.Paging{PageSize: 100})
c.HTML(http.StatusOK, "search.gohtml", gin.H{"Search": search, "Holidays": mapHolidays(holidays).Holidays})
})
g.GET("/dialogs/check-is-a-holiday", func(c *gin.Context) {
c.HTML(http.StatusOK, "check-is-a-holiday.gohtml", gin.H{})
})
2023-06-23 17:31:02 +00:00
log.Fatal(http.ListenAndServe(":5281", g))
2023-06-16 07:42:50 +00:00
}
2023-06-23 17:31:02 +00:00
func loadTemplates(g *gin.Engine) {
g.SetFuncMap(template.FuncMap{
2023-06-20 14:10:46 +00:00
"boolcmp": func(value *bool, expected string) bool {
if value == nil {
return expected == "nil"
} else {
return (*value && expected == "true") || (!(*value) && expected == "false")
}
},
"deferint": func(value *int) int { return *value },
"intpeq": func(selected *int, value int) bool {
if selected != nil {
return *selected == value
}
return false
},
2023-06-23 17:31:02 +00:00
})
g.LoadHTMLFiles(
"templates/index.gohtml",
"templates/search.gohtml",
"templates/documentation.gohtml",
"templates/admin_dashboard.gohtml",
"templates/dialogs/add-holiday.gohtml",
"templates/dialogs/edit-holiday.gohtml",
"templates/dialogs/delete-holiday.gohtml",
"templates/dialogs/check-is-a-holiday.gohtml",
)
2023-06-23 17:31:02 +00:00
}
2023-06-20 14:10:46 +00:00
2023-06-23 17:31:02 +00:00
func setupAdminDashboard(adminDashboard *gin.RouterGroup, service holiday.Service) {
adminDashboard.Use(gin.BasicAuth(loadAuth()))
2023-06-20 14:10:46 +00:00
adminDashboard.GET("/", func(c *gin.Context) {
search := holiday.Search{Country: "HR", Year: new(int)}
*search.Year = time.Now().Year()
if err := c.ShouldBindQuery(&search); err != nil {
c.AbortWithError(http.StatusBadRequest, err)
return
2023-06-20 14:10:46 +00:00
}
holidays, _ := service.Find(search, holiday.Paging{PageSize: 100})
holidayResponse := mapHolidays(holidays)
response := map[string]any{}
response["holidays"] = holidayResponse
response["search"] = search
c.HTML(http.StatusOK, "admin_dashboard.gohtml", response)
2023-06-20 14:10:46 +00:00
})
adminDashboard.POST("/holidays", func(c *gin.Context) {
2023-06-23 17:31:02 +00:00
request := struct {
Id *string `form:"id"`
Name string `form:"name" binding:"required,min=1"`
Description string `form:"description"`
IsStateHoliday bool `form:"state_holiday"`
IsReligiousHoliday bool `form:"religious_holiday"`
2023-06-23 17:31:02 +00:00
Country string `form:"country" binding:"len=2"`
Date time.Time `form:"date" time_format:"2006-01-02"`
}{}
if err := c.ShouldBind(&request); err != nil {
c.AbortWithError(http.StatusBadRequest, err)
return
2023-06-20 14:10:46 +00:00
}
hol := holiday.Holiday{
2023-06-23 17:31:02 +00:00
Country: request.Country,
Date: request.Date,
Name: request.Name,
Description: request.Description,
IsStateHoliday: request.IsStateHoliday,
IsReligiousHoliday: request.IsReligiousHoliday,
2023-06-20 14:10:46 +00:00
}
var err error
2023-06-23 17:31:02 +00:00
if request.Id != nil {
hol.Id = uuid.MustParse(*request.Id)
2023-06-20 14:10:46 +00:00
hol, err = service.Update(hol)
} else {
hol, err = service.Create(hol)
}
if err != nil {
2023-06-23 17:31:02 +00:00
c.AbortWithError(http.StatusInternalServerError, err)
2023-06-20 14:10:46 +00:00
} else {
c.Redirect(http.StatusSeeOther, "/admin?country="+request.Country+"&year="+strconv.FormatInt(int64(request.Date.Year()), 10))
2023-06-20 14:10:46 +00:00
}
})
adminDashboard.POST("/holidays/:id/delete", func(c *gin.Context) {
id := uuid.MustParse(c.Param("id"))
hol, err := service.FindById(id)
if err != nil {
c.AbortWithError(http.StatusNotFound, err)
2023-06-23 17:31:02 +00:00
return
2023-06-20 14:10:46 +00:00
}
if err := service.Delete(id); err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
c.Redirect(http.StatusSeeOther, "/admin?country="+hol.Country+"&year="+strconv.FormatInt(int64(hol.Date.Year()), 10))
})
adminDashboard.GET("/dialogs/add-holiday", func(c *gin.Context) {
c.HTML(http.StatusOK, "add-holiday.gohtml", gin.H{})
})
adminDashboard.GET("/dialogs/edit-holiday", func(c *gin.Context) {
id := uuid.MustParse(c.Query("id"))
hol, err := service.FindById(id)
2023-06-23 17:31:02 +00:00
if err != nil {
c.AbortWithError(http.StatusNotFound, err)
return
2023-06-20 14:10:46 +00:00
}
c.HTML(http.StatusOK, "edit-holiday.gohtml", gin.H{"Holiday": hol})
2023-06-23 17:31:02 +00:00
})
adminDashboard.GET("/dialogs/delete-holiday", func(c *gin.Context) {
id := uuid.MustParse(c.Query("id"))
hol, err := service.FindById(id)
if err != nil {
c.AbortWithError(http.StatusNotFound, err)
2023-06-23 17:31:02 +00:00
return
}
c.HTML(http.StatusOK, "delete-holiday.gohtml", gin.H{"Holiday": hol})
2023-06-20 14:10:46 +00:00
})
}
2023-06-16 07:42:50 +00:00
2023-06-23 17:31:02 +00:00
func loadAuth() map[string]string {
2023-06-20 14:10:46 +00:00
credentials := envMustExist("AUTH_KEY")
values := strings.Split(credentials, ":")
return map[string]string{values[0]: values[1]}
2023-06-16 07:42:50 +00:00
}