switching form bindings/validation and redirecting to proper 500 page

This commit is contained in:
BroodjeAap 2022-07-24 19:56:40 +00:00
parent 875b71b504
commit de64cd6aab
6 changed files with 72 additions and 56 deletions

2
go.mod
View file

@ -6,6 +6,7 @@ require (
github.com/antchfx/htmlquery v1.2.5 github.com/antchfx/htmlquery v1.2.5
github.com/gin-contrib/multitemplate v0.0.0-20220705015713-e21a0ba39de3 github.com/gin-contrib/multitemplate v0.0.0-20220705015713-e21a0ba39de3
github.com/gin-gonic/gin v1.8.1 github.com/gin-gonic/gin v1.8.1
github.com/go-playground/validator/v10 v10.11.0
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
github.com/spf13/viper v1.12.0 github.com/spf13/viper v1.12.0
golang.org/x/net v0.0.0-20220722155237-a158d28d115b golang.org/x/net v0.0.0-20220722155237-a158d28d115b
@ -19,7 +20,6 @@ require (
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.0 // indirect
github.com/goccy/go-json v0.9.10 // indirect github.com/goccy/go-json v0.9.10 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect

41
main.go
View file

@ -38,17 +38,12 @@ func (web Web) newWatch(c *gin.Context) {
} }
func (web Web) createWatch(c *gin.Context) { func (web Web) createWatch(c *gin.Context) {
interval, err := strconv.Atoi(c.PostForm("interval")) var watch Watch
errMap, err := bindAndValidateWatch(&watch, c)
if err != nil { if err != nil {
c.Redirect(http.StatusSeeOther, "/watch/new") c.HTML(http.StatusBadRequest, "500", errMap)
return
} }
web.db.Create(&watch)
watch := &Watch{
Name: c.PostForm("name"),
Interval: interval,
}
web.db.Create(watch)
c.Redirect(http.StatusSeeOther, fmt.Sprintf("/watch/view/%d", watch.ID)) c.Redirect(http.StatusSeeOther, fmt.Sprintf("/watch/view/%d", watch.ID))
} }
@ -72,29 +67,15 @@ func (web Web) viewWatch(c *gin.Context) {
} }
func (web Web) createURL(c *gin.Context) { func (web Web) createURL(c *gin.Context) {
watch_id, err := strconv.ParseUint(c.PostForm("watch_id"), 10, 64) var url URL
errMap, err := bindAndValidateURL(&url, c)
if err != nil { if err != nil {
c.Redirect(http.StatusSeeOther, "/watch/new") log.Print(err)
return // TODO response c.HTML(http.StatusInternalServerError, "500", errMap)
}
name := c.PostForm("name")
if name == "" {
c.Redirect(http.StatusSeeOther, "/watch/new")
return return
} }
url := c.PostForm("url") web.db.Create(url)
if url == "" { c.Redirect(http.StatusSeeOther, fmt.Sprintf("/watch/view/%d", url.WatchID))
c.Redirect(http.StatusSeeOther, "/watch/new")
return
}
url_model := &URL{
WatchID: uint(watch_id),
Name: name,
URL: url,
}
web.db.Create(url_model)
c.Redirect(http.StatusSeeOther, fmt.Sprintf("/watch/view/%d", watch_id))
} }
func (web Web) createQuery(c *gin.Context) { func (web Web) createQuery(c *gin.Context) {
@ -253,6 +234,8 @@ func main() {
templates.AddFromFiles("newWatch", "templates/base.html", "templates/newWatch.html") templates.AddFromFiles("newWatch", "templates/base.html", "templates/newWatch.html")
templates.AddFromFiles("viewWatch", "templates/base.html", "templates/viewWatch.html") templates.AddFromFiles("viewWatch", "templates/base.html", "templates/viewWatch.html")
templates.AddFromFiles("editQuery", "templates/base.html", "templates/editQuery.html") templates.AddFromFiles("editQuery", "templates/base.html", "templates/editQuery.html")
templates.AddFromFiles("500", "templates/base.html", "templates/500.html")
router.HTMLRender = templates router.HTMLRender = templates
router.GET("/", web.index) router.GET("/", web.index)

View file

@ -6,36 +6,36 @@ import (
type Watch struct { type Watch struct {
gorm.Model gorm.Model
Name string Name string `form:"name" yaml:"name" binding:"required" validate:"min=1"`
Interval int Interval int `form:"interval" yaml:"interval" binding:"required"`
URLs []URL URLs []URL
} }
type URL struct { type URL struct {
gorm.Model gorm.Model
WatchID uint WatchID uint `form:"watch_id" yaml:"watch_id" binding:"required"`
Watch Watch Watch *Watch `form:"watch" yaml:"watch" validate:"omitempty"`
Name string Name string `form:"name" yaml:"name" binding:"required"`
URL string URL string `form:"url" yaml:"url" binding:"required,url"`
Queries []Query Queries []Query
} }
type Query struct { type Query struct {
gorm.Model gorm.Model
URLID uint URLID uint `form:"url_id" yaml:"url_id" binding:"required"`
URL URL URL URL
Name string Name string `form:"name" yaml:"name" binding:"required"`
Type string Type string `form:"type" yaml:"type" binding:"required"`
Query string Query string `form:"query" yaml:"query" binding:"required"`
Filters []Filter Filters []Filter
} }
type Filter struct { type Filter struct {
gorm.Model gorm.Model
QueryID uint QueryID uint `form:"query_id" yaml:"query_id" binding:"required"`
Query Query Query Query
Name string Name string `form:"name" yaml:"name" binding:"required"`
Type string Type string `form:"type" yaml:"type" binding:"required"`
From string From string `form:"from" yaml:"from" binding:"required"`
To string To string `form:"to" yaml:"to" binding:"required"`
} }

3
templates/500.html Normal file
View file

@ -0,0 +1,3 @@
{{define "content"}}
<h1>Something went wrong, try again.</h1>
{{end}}

View file

@ -1,12 +1,3 @@
{{template "base" .}}
{{define "title"}}
{{end}}
{{define "navbar"}}
{{end}}
{{define "head"}}
{{end}}
{{define "left"}}
{{end}}
{{define "content"}} {{define "content"}}
<form action="/watch/create" method="post"> <form action="/watch/create" method="post">
<div class="mb-3"> <div class="mb-3">
@ -19,6 +10,5 @@
</div> </div>
<input type="submit" class="btn btn-primary mb-3" value="Create"> <input type="submit" class="btn btn-primary mb-3" value="Create">
</form> </form>
{{end}} {{ . }}
{{define "right"}}
{{end}} {{end}}

40
util.go Normal file
View file

@ -0,0 +1,40 @@
package main
import (
"errors"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
)
func bindAndValidateWatch(watch *Watch, c *gin.Context) (map[string]string, error) {
err := c.ShouldBind(watch)
return validate(err), err
}
func bindAndValidateURL(url *URL, c *gin.Context) (map[string]string, error) {
err := c.ShouldBind(url)
return validate(err), err
}
func prettyError(fieldError validator.FieldError) string {
switch fieldError.Tag() {
case "required":
return fieldError.Field() + " is required"
default:
return "No prettyError for " + fieldError.Tag()
}
}
func validate(err error) map[string]string {
out := make(map[string]string)
if err != nil {
var ve validator.ValidationErrors
if errors.As(err, &ve) {
for _, fe := range ve {
out[fe.Field()] = prettyError(fe)
}
}
}
return out
}