package main import ( "errors" "github.com/gin-gonic/gin" "net/http" "strconv" ) type ViewModel struct { Users []User CurrentUser int Allowances []Allowance Tasks []Task History []History Error string } func loadWebEndpoints(router *gin.Engine) { router.LoadHTMLFiles("web.gohtml") router.GET("/", renderIndex) router.GET("/login", renderLogin) router.POST("/createTask", renderCreateTask) router.GET("/completeTask", renderCompleteTask) router.POST("/createAllowance", renderCreateAllowance) router.GET("/completeAllowance", renderCompleteAllowance) } func renderLogin(c *gin.Context) { if c.Query("user") != "" { c.SetCookie("user", c.Query("user"), 3600, "/", "localhost", false, true) } c.Redirect(http.StatusFound, "/") } func renderIndex(c *gin.Context) { currentUser := getCurrentUser(c) if currentUser == nil { return } renderWithUser(c, *currentUser) } func renderCreateTask(c *gin.Context) { currentUser := getCurrentUser(c) if currentUser == nil { return } name := c.PostForm("name") rewardStr := c.PostForm("reward") reward, err := strconv.ParseFloat(rewardStr, 64) if err != nil { renderError(c, http.StatusBadRequest, err) return } if name == "" || reward <= 0 { renderError(c, http.StatusBadRequest, err) return } _, err = db.CreateTask(&CreateTaskRequest{ Name: name, Reward: reward, }) if err != nil { renderError(c, http.StatusInternalServerError, err) return } c.Redirect(http.StatusFound, "/") } func renderCompleteTask(c *gin.Context) { taskIDStr := c.Query("task") taskID, err := strconv.Atoi(taskIDStr) if err != nil { renderError(c, http.StatusBadRequest, err) return } err = db.CompleteTask(taskID) if err != nil { renderError(c, http.StatusInternalServerError, err) return } c.Redirect(http.StatusFound, "/") } func renderCreateAllowance(c *gin.Context) { currentUser := getCurrentUser(c) if currentUser == nil { return } name := c.PostForm("name") targetStr := c.PostForm("target") target, err := strconv.ParseFloat(targetStr, 64) if err != nil { renderError(c, http.StatusBadRequest, err) return } weightStr := c.PostForm("weight") weight, err := strconv.ParseFloat(weightStr, 64) if err != nil { renderError(c, http.StatusBadRequest, err) return } if name == "" || target <= 0 || weight <= 0 { renderError(c, http.StatusBadRequest, err) return } _, err = db.CreateAllowance(*currentUser, &CreateAllowanceRequest{ Name: name, Target: target, Weight: weight, }) if err != nil { renderError(c, http.StatusInternalServerError, err) return } c.Redirect(http.StatusFound, "/") } func renderCompleteAllowance(c *gin.Context) { currentUser := getCurrentUser(c) if currentUser == nil { return } allowanceIDStr := c.Query("allowance") allowanceID, err := strconv.Atoi(allowanceIDStr) if err != nil { renderError(c, http.StatusBadRequest, err) return } err = db.CompleteAllowance(*currentUser, allowanceID) if err != nil { renderError(c, http.StatusInternalServerError, err) return } c.Redirect(http.StatusFound, "/") } func getCurrentUser(c *gin.Context) *int { currentUserStr, err := c.Cookie("user") if errors.Is(err, http.ErrNoCookie) { renderNoUser(c) return nil } if err != nil { unsetUserCookie(c) return nil } currentUser, err := strconv.Atoi(currentUserStr) if err != nil { unsetUserCookie(c) return nil } userExists, err := db.UserExists(currentUser) if !userExists || err != nil { unsetUserCookie(c) return nil } return ¤tUser } func unsetUserCookie(c *gin.Context) { c.SetCookie("user", "", -1, "/", "localhost", false, true) c.Redirect(http.StatusFound, "/") } func renderNoUser(c *gin.Context) { users, err := db.GetUsers() if err != nil { renderError(c, http.StatusInternalServerError, err) return } c.HTML(http.StatusOK, "web.gohtml", ViewModel{ Users: users, }) } func renderWithUser(c *gin.Context, currentUser int) { users, err := db.GetUsers() if err != nil { renderError(c, http.StatusInternalServerError, err) return } allowances, err := db.GetUserAllowances(currentUser) if err != nil { renderError(c, http.StatusInternalServerError, err) return } tasks, err := db.GetTasks() if err != nil { renderError(c, http.StatusInternalServerError, err) return } history, err := db.GetHistory(currentUser) if err != nil { renderError(c, http.StatusInternalServerError, err) return } c.HTML(http.StatusOK, "web.gohtml", ViewModel{ Users: users, CurrentUser: currentUser, Allowances: allowances, Tasks: tasks, History: history, }) } func renderError(c *gin.Context, statusCode int, err error) { c.HTML(statusCode, "web.gohtml", ViewModel{ Error: err.Error(), }) }