switched to bindings + validators for forms
This commit is contained in:
parent
de64cd6aab
commit
18449ed0a5
6 changed files with 81 additions and 151 deletions
75
main.go
75
main.go
|
@ -42,6 +42,7 @@ func (web Web) createWatch(c *gin.Context) {
|
|||
errMap, err := bindAndValidateWatch(&watch, c)
|
||||
if err != nil {
|
||||
c.HTML(http.StatusBadRequest, "500", errMap)
|
||||
return
|
||||
}
|
||||
web.db.Create(&watch)
|
||||
c.Redirect(http.StatusSeeOther, fmt.Sprintf("/watch/view/%d", watch.ID))
|
||||
|
@ -74,83 +75,37 @@ func (web Web) createURL(c *gin.Context) {
|
|||
c.HTML(http.StatusInternalServerError, "500", errMap)
|
||||
return
|
||||
}
|
||||
web.db.Create(url)
|
||||
web.db.Create(&url)
|
||||
c.Redirect(http.StatusSeeOther, fmt.Sprintf("/watch/view/%d", url.WatchID))
|
||||
}
|
||||
|
||||
func (web Web) createQuery(c *gin.Context) {
|
||||
watch_id, err := strconv.ParseUint(c.PostForm("watch_id"), 10, 64)
|
||||
watch_id, err := strconv.ParseUint(c.PostForm("w_id"), 10, 64)
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusSeeOther, "/watch/new")
|
||||
return // TODO response
|
||||
log.Print(err)
|
||||
c.HTML(http.StatusInternalServerError, "500", gin.H{})
|
||||
return
|
||||
}
|
||||
url_id, err := strconv.ParseUint(c.PostForm("url_id"), 10, 64)
|
||||
var query Query
|
||||
errMap, err := bindAndValidateQuery(&query, c)
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusSeeOther, "/watch/new")
|
||||
return // TODO response
|
||||
}
|
||||
name := c.PostForm("name")
|
||||
if name == "" {
|
||||
c.Redirect(http.StatusSeeOther, "/watch/new")
|
||||
c.HTML(http.StatusBadRequest, "500", errMap)
|
||||
return
|
||||
}
|
||||
typ := c.PostForm("type")
|
||||
if typ == "" {
|
||||
c.Redirect(http.StatusSeeOther, "/watch/new")
|
||||
return
|
||||
}
|
||||
query := c.PostForm("query")
|
||||
if query == "" {
|
||||
c.Redirect(http.StatusSeeOther, "/watch/new")
|
||||
return
|
||||
}
|
||||
|
||||
query_model := &Query{
|
||||
URLID: uint(url_id),
|
||||
Name: name,
|
||||
Type: typ,
|
||||
Query: query,
|
||||
}
|
||||
web.db.Create(query_model)
|
||||
web.db.Create(&query)
|
||||
c.Redirect(http.StatusSeeOther, fmt.Sprintf("/watch/view/%d", watch_id))
|
||||
}
|
||||
|
||||
func (web Web) createFilter(c *gin.Context) {
|
||||
query_id, err := strconv.ParseUint(c.PostForm("query_id"), 10, 64)
|
||||
var filter Filter
|
||||
errMap, err := bindAndValidateFilter(&filter, c)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
c.Redirect(http.StatusSeeOther, "/watch/new")
|
||||
return // TODO response
|
||||
}
|
||||
name := c.PostForm("name")
|
||||
if name == "" {
|
||||
log.Print(name)
|
||||
c.Redirect(http.StatusSeeOther, "/watch/new")
|
||||
c.HTML(http.StatusBadRequest, "500", errMap)
|
||||
return
|
||||
}
|
||||
typ := c.PostForm("type")
|
||||
if typ == "" {
|
||||
log.Print(typ)
|
||||
c.Redirect(http.StatusSeeOther, "/watch/new")
|
||||
return
|
||||
}
|
||||
from := c.PostForm("from")
|
||||
if from == "" {
|
||||
log.Print(from)
|
||||
c.Redirect(http.StatusSeeOther, "/watch/new")
|
||||
return
|
||||
}
|
||||
to := c.PostForm("to")
|
||||
log.Print("To:", to)
|
||||
filter_model := &Filter{
|
||||
QueryID: uint(query_id),
|
||||
Name: name,
|
||||
Type: typ,
|
||||
From: from,
|
||||
To: to,
|
||||
}
|
||||
web.db.Create(filter_model)
|
||||
c.Redirect(http.StatusSeeOther, fmt.Sprintf("/query/edit/%d", query_id))
|
||||
web.db.Create(&filter)
|
||||
c.Redirect(http.StatusSeeOther, fmt.Sprintf("/query/edit/%d", filter.QueryID))
|
||||
}
|
||||
|
||||
func (web Web) editQuery(c *gin.Context) {
|
||||
|
|
24
models.go
24
models.go
|
@ -6,36 +6,36 @@ import (
|
|||
|
||||
type Watch struct {
|
||||
gorm.Model
|
||||
Name string `form:"name" yaml:"name" binding:"required" validate:"min=1"`
|
||||
Name string `form:"watch_name" yaml:"watch_name" binding:"required" validate:"min=1"`
|
||||
Interval int `form:"interval" yaml:"interval" binding:"required"`
|
||||
URLs []URL
|
||||
}
|
||||
|
||||
type URL struct {
|
||||
gorm.Model
|
||||
WatchID uint `form:"watch_id" yaml:"watch_id" binding:"required"`
|
||||
WatchID uint `form:"url_watch_id" yaml:"url_watch_id" binding:"required"`
|
||||
Watch *Watch `form:"watch" yaml:"watch" validate:"omitempty"`
|
||||
Name string `form:"name" yaml:"name" binding:"required"`
|
||||
URL string `form:"url" yaml:"url" binding:"required,url"`
|
||||
Name string `form:"url_name" yaml:"url_name" binding:"required" validate:"min=1"`
|
||||
URL string `form:"url" yaml:"url" binding:"required,url" validate:"min=1"`
|
||||
Queries []Query
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
gorm.Model
|
||||
URLID uint `form:"url_id" yaml:"url_id" binding:"required"`
|
||||
URL URL
|
||||
Name string `form:"name" yaml:"name" binding:"required"`
|
||||
Type string `form:"type" yaml:"type" binding:"required"`
|
||||
URLID uint `form:"query_url_id" yaml:"query_url_id" binding:"required"`
|
||||
URL *URL
|
||||
Name string `form:"query_name" yaml:"query_name" binding:"required" validate:"min=1"`
|
||||
Type string `form:"query_type" yaml:"query_type" binding:"required" validate:"oneof=css xpath regex json"`
|
||||
Query string `form:"query" yaml:"query" binding:"required"`
|
||||
Filters []Filter
|
||||
}
|
||||
|
||||
type Filter struct {
|
||||
gorm.Model
|
||||
QueryID uint `form:"query_id" yaml:"query_id" binding:"required"`
|
||||
Query Query
|
||||
Name string `form:"name" yaml:"name" binding:"required"`
|
||||
Type string `form:"type" yaml:"type" binding:"required"`
|
||||
QueryID uint `form:"filter_query_id" yaml:"filter_query_id" binding:"required"`
|
||||
Query *Query
|
||||
Name string `form:"filter_name" yaml:"filter_name" binding:"required" validate:"min=1"`
|
||||
Type string `form:"filter_type" yaml:"filter_type" binding:"required" validate:"oneof=replace regex substring"`
|
||||
From string `form:"from" yaml:"from" binding:"required"`
|
||||
To string `form:"to" yaml:"to" binding:"required"`
|
||||
}
|
||||
|
|
|
@ -66,30 +66,27 @@
|
|||
<div class="modal-body">
|
||||
|
||||
<ul class="nav nav-tabs" id="newFilterTabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="replace-tab" data-bs-toggle="tab" data-bs-target="#replace-tab-pane" type="button" role="tab" aria-controls="home-tab-pane" aria-selected="true">Replace</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="regex-tab" data-bs-toggle="tab" data-bs-target="#regex-tab-pane" type="button" role="tab" aria-controls="profile-tab-pane" aria-selected="false">Regex</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="substring-tab" data-bs-toggle="tab" data-bs-target="#substring-tab-pane" type="button" role="tab" aria-controls="contact-tab-pane" aria-selected="false">Substring</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="lua-tab" data-bs-toggle="tab" data-bs-target="#lua-tab-pane" type="button" role="tab" aria-selected="false">Lua</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="replace-tab" data-bs-toggle="tab" data-bs-target="#replace-tab-pane" type="button" role="tab" aria-controls="home-tab-pane" aria-selected="true">Replace</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="regex-tab" data-bs-toggle="tab" data-bs-target="#regex-tab-pane" type="button" role="tab" aria-controls="profile-tab-pane" aria-selected="false">Regex</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="substring-tab" data-bs-toggle="tab" data-bs-target="#substring-tab-pane" type="button" role="tab" aria-controls="contact-tab-pane" aria-selected="false">Substring</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content" id="newFilterTabsContent">
|
||||
<div class="tab-pane fade show active" id="replace-tab-pane" role="tabpanel" aria-labelledby="replace-tab" tabindex="0">
|
||||
|
||||
<form action="/filter/create" method="post">
|
||||
<div class="mb-3 m-3 row">
|
||||
<input type="hidden" name="query_id" value="{{ .Query.ID }}" >
|
||||
<input type="hidden" name="type" value="replace" >
|
||||
<input type="hidden" name="filter_query_id" value="{{ .Query.ID }}" >
|
||||
<input type="hidden" name="filter_type" value="replace" >
|
||||
|
||||
<label for="nameInput" class="col-sm-2 col-form-label">Name:</label>
|
||||
<div class="col-sm-10 p-2">
|
||||
<input type="text" class="form-control" name="name" id="nameInput" placeholder="Name">
|
||||
<input type="text" class="form-control" name="filter_name" id="nameInput" placeholder="Name">
|
||||
</div>
|
||||
<label for="fromInput" class="col-sm-2 col-form-label">From:</label>
|
||||
<div class="col-sm-10 p-2">
|
||||
|
@ -106,12 +103,12 @@
|
|||
<div class="tab-pane fade" id="regex-tab-pane" role="tabpanel" aria-labelledby="regex-tab" tabindex="0">
|
||||
<form action="/filter/create" method="post">
|
||||
<div class="mb-3 m-3 row">
|
||||
<input type="hidden" name="query_id" value="{{ .Query.ID }}" >
|
||||
<input type="hidden" name="type" value="regex" >
|
||||
<input type="hidden" name="filter_query_id" value="{{ .Query.ID }}" >
|
||||
<input type="hidden" name="filter_type" value="regex" >
|
||||
|
||||
<label for="nameInput" class="col-sm-2 col-form-label">Name:</label>
|
||||
<div class="col-sm-10 p-2">
|
||||
<input type="text" class="form-control" name="name" id="nameInput" placeholder="Name">
|
||||
<input type="text" class="form-control" name="filter_name" id="nameInput" placeholder="Name">
|
||||
</div>
|
||||
<label for="fromInput" class="col-sm-2 col-form-label">From:</label>
|
||||
<div class="col-sm-10 p-2">
|
||||
|
@ -128,13 +125,13 @@
|
|||
<div class="tab-pane fade" id="substring-tab-pane" role="tabpanel" aria-labelledby="substring-tab" tabindex="0">
|
||||
<form action="/filter/create" method="post">
|
||||
<div class="mb-3 m-3 row">
|
||||
<input type="hidden" name="query_id" value="{{ .Query.ID }}" >
|
||||
<input type="hidden" name="type" value="substring" >
|
||||
<input type="hidden" name="filter_query_id" value="{{ .Query.ID }}" >
|
||||
<input type="hidden" name="filter_type" value="substring" >
|
||||
<input type="hidden" name="to" value="-" >
|
||||
|
||||
<label for="nameInput" class="col-sm-2 col-form-label">Name:</label>
|
||||
<div class="col-sm-10 p-2">
|
||||
<input type="text" class="form-control" name="name" id="nameInput" placeholder="Name">
|
||||
<input type="text" class="form-control" name="filter_name" id="nameInput" placeholder="Name">
|
||||
</div>
|
||||
<label for="fromInput" class="col-sm-2 col-form-label">From:</label>
|
||||
<div class="col-sm-10 p-2">
|
||||
|
@ -144,27 +141,6 @@
|
|||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="lua-tab-pane" role="tabpanel" aria-labelledby="lua-tab" tabindex="0">
|
||||
<form action="/filter/create" method="post">
|
||||
<div class="mb-3 m-3 row">
|
||||
<input type="hidden" name="query_id" value="{{ .Query.ID }}" >
|
||||
<input type="hidden" name="type" value="lua" >
|
||||
<input type="hidden" name="to" value="-" >
|
||||
|
||||
<label for="nameInput" class="col-sm-2 col-form-label">Name:</label>
|
||||
<div class="col-sm-10 p-2">
|
||||
<input type="text" class="form-control" name="name" id="nameInput" placeholder="Name">
|
||||
</div>
|
||||
<label for="fromInput" class="col-sm-2 col-form-label">From:</label>
|
||||
<select name="from" class="form-select"> <!-- TODO Lua stuff -->
|
||||
<option>lua_func1</option>
|
||||
<option>lua_func2</option>
|
||||
<option>lua_func3</option>
|
||||
</select>
|
||||
<button class="btn btn-primary mt-4">Add Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<form action="/watch/create" method="post">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Watch Name</label>
|
||||
<input name="name" type="text" class="form-control" id="name" placeholder="Watch">
|
||||
<input name="watch_name" type="text" class="form-control" id="name" placeholder="Watch">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="interval" class="form-label">Interval (seconds) - TODO </label>
|
||||
|
@ -10,5 +10,4 @@
|
|||
</div>
|
||||
<input type="submit" class="btn btn-primary mb-3" value="Create">
|
||||
</form>
|
||||
{{ . }}
|
||||
{{end}}
|
|
@ -26,13 +26,16 @@
|
|||
<div class="col h4 text-center" >{{ .Name }}</div>
|
||||
<div class="col h5 text-end"><a class="btn btn-success btn-sm" href="/query/edit/{{ .ID }}">Edit</a></div>
|
||||
</div>
|
||||
<div class="text-center text-muted">
|
||||
{{ .Query }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form action="/filter/create" method="post">
|
||||
<input type="hidden" name="query_id" value="{{ .ID }}" >
|
||||
<input type="hidden" name="watch_id" value="{{ $.ID }}" >
|
||||
<table class="table table-hover caption-top">
|
||||
<tbody>
|
||||
<input type="hidden" name="query_id" value="{{ .ID }}" >
|
||||
<input type="hidden" name="w_id" value="{{ $.ID }}" >
|
||||
<table class="table table-hover caption-top">
|
||||
<tbody>
|
||||
{{ if .Filters }}
|
||||
{{ range .Filters }}
|
||||
<tr>
|
||||
<td>{{ .Name }}</td>
|
||||
|
@ -42,48 +45,35 @@
|
|||
<td></td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
<tr>
|
||||
<td><input type="text" class="form-control" name="name" placeholder="Filter Name"></td>
|
||||
<td>
|
||||
<select class="form-control" id="type" name="type">
|
||||
<option>Replace</option>
|
||||
<option>Regex Replace</option>
|
||||
<option>Substring</option>
|
||||
<option>Lua</option>
|
||||
</select>
|
||||
</td>
|
||||
<td><input type="text" class="form-control" name="from" placeholder="From"></td>
|
||||
<td><input type="text" class="form-control" name="to" placeholder="To"></td>
|
||||
<td><button class="btn btn-primary">Add Filter</button></td>
|
||||
<td class="text-center h3">No filters yet, click "Edit" to add</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="row">
|
||||
<div class="col-2">{{ .Type }}</div>
|
||||
<div class="col-8">{{ .Query }}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
<form action="/query/create" method="post">
|
||||
<input type="hidden" name="url_id" value="{{ .ID }}" >
|
||||
<input type="hidden" name="watch_id" value="{{ $.ID }}" >
|
||||
<input type="hidden" name="query_url_id" value="{{ .ID }}" >
|
||||
<input type="hidden" name="w_id" value="{{ $.ID }}" >
|
||||
<table class="table table-hover caption-top">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<input type="text" class="form-control" name="name" placeholder="Query Name">
|
||||
<input type="text" class="form-control" name="query_name" placeholder="Query Name">
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-control" id="type" name="type">
|
||||
<option>CSS Selector</option>
|
||||
<option>XPath</option>
|
||||
<option>Regex</option>
|
||||
<option>JSON</option>
|
||||
<option>Lua</option>
|
||||
<select class="form-control" id="query_type" name="query_type">
|
||||
<option value="css">CSS Selector</option>
|
||||
<option value="xpath">XPath</option>
|
||||
<option value="regex">Regex</option>
|
||||
<option value="json">JSON</option>
|
||||
<!-- additions/changes should also be added to Query.Type oneof validator -->
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -106,13 +96,13 @@
|
|||
<div class="card-body">
|
||||
<form action="/url/create" method="post">
|
||||
<div class="form-group mb-2">
|
||||
<input type="text" class="form-control" name="name" id="urlName" placeholder="URL Name">
|
||||
<input type="text" class="form-control" name="url_name" id="urlName" placeholder="URL Name">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<input type="url" class="form-control" name="url" id="url" placeholder="URL">
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="watch_id" value="{{ .ID }}" >
|
||||
<input type="hidden" name="url_watch_id" value="{{ .ID }}" >
|
||||
<input class="btn btn-primary" type="submit" value="Create URL">
|
||||
</form>
|
||||
</div>
|
||||
|
|
10
util.go
10
util.go
|
@ -17,6 +17,16 @@ func bindAndValidateURL(url *URL, c *gin.Context) (map[string]string, error) {
|
|||
return validate(err), err
|
||||
}
|
||||
|
||||
func bindAndValidateQuery(query *Query, c *gin.Context) (map[string]string, error) {
|
||||
err := c.ShouldBind(query)
|
||||
return validate(err), err
|
||||
}
|
||||
|
||||
func bindAndValidateFilter(filter *Filter, c *gin.Context) (map[string]string, error) {
|
||||
err := c.ShouldBind(filter)
|
||||
return validate(err), err
|
||||
}
|
||||
|
||||
func prettyError(fieldError validator.FieldError) string {
|
||||
switch fieldError.Tag() {
|
||||
case "required":
|
||||
|
|
Loading…
Add table
Reference in a new issue