added bunch of stuff working Watch/URL/Query/Filter

This commit is contained in:
BroodjeAap 2022-07-24 14:31:06 +00:00
parent 5beea02e83
commit 68869532ff
7 changed files with 438 additions and 59 deletions

5
go.mod
View file

@ -3,21 +3,25 @@ module broodjeaap.net/go-watch-and-tel
go 1.18
require (
github.com/antchfx/htmlquery v1.2.5
github.com/gin-contrib/multitemplate v0.0.0-20220705015713-e21a0ba39de3
github.com/gin-gonic/gin v1.8.1
github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1
github.com/spf13/viper v1.12.0
golang.org/x/net v0.0.0-20220722155237-a158d28d115b
gorm.io/driver/sqlite v1.3.6
gorm.io/gorm v1.23.8
)
require (
github.com/antchfx/xpath v1.2.1 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/gin-contrib/sse v0.1.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/validator/v10 v10.11.0 // indirect
github.com/goccy/go-json v0.9.10 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
@ -38,7 +42,6 @@ require (
github.com/subosito/gotenv v1.3.0 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/net v0.0.0-20220708220712-1185a9018129 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/protobuf v1.28.0 // indirect

11
go.sum
View file

@ -38,6 +38,10 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/antchfx/htmlquery v1.2.5 h1:1lXnx46/1wtv1E/kzmH8vrfMuUKYgkdDBA9pIdMJnk4=
github.com/antchfx/htmlquery v1.2.5/go.mod h1:2MCVBzYVafPBmKbrmwB9F5xdd+IEgRY61ci2oOsOQVw=
github.com/antchfx/xpath v1.2.1 h1:qhp4EW6aCOVr5XIkT+l6LJ9ck/JsUH/yyauNgTQkBF8=
github.com/antchfx/xpath v1.2.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
@ -86,6 +90,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@ -296,6 +302,7 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
@ -309,8 +316,8 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220708220712-1185a9018129 h1:vucSRfWwTsoXro7P+3Cjlr6flUMtzCwzlvkxEQtHHB0=
golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=

68
main.go
View file

@ -67,7 +67,7 @@ func (web Web) viewWatch(c *gin.Context) {
id := c.Param("id")
var watch Watch
web.db.Model(&Watch{}).Preload("URLs.Queries").First(&watch, id)
web.db.Model(&Watch{}).Preload("URLs.Queries.Filters").First(&watch, id)
c.HTML(http.StatusOK, "viewWatch", watch)
}
@ -113,13 +113,13 @@ func (web Web) createQuery(c *gin.Context) {
c.Redirect(http.StatusSeeOther, "/watch/new")
return
}
query := c.PostForm("query")
if query == "" {
typ := c.PostForm("type")
if typ == "" {
c.Redirect(http.StatusSeeOther, "/watch/new")
return
}
typ := c.PostForm("type")
if typ == "" {
query := c.PostForm("query")
if query == "" {
c.Redirect(http.StatusSeeOther, "/watch/new")
return
}
@ -134,6 +134,59 @@ func (web Web) createQuery(c *gin.Context) {
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)
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")
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))
}
func (web Web) editQuery(c *gin.Context) {
query_id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
c.Redirect(http.StatusSeeOther, "/watch/new")
return // TODO response
}
var query Query
web.db.Preload("URL.Watch").Preload("Filters").Preload("URL").First(&query, query_id)
c.HTML(http.StatusOK, "editQuery", gin.H{
"Query": query,
"currentResult": getQueryResult(&query),
})
}
func passiveBot(bot *tgbotapi.BotAPI) {
u := tgbotapi.NewUpdate(0)
u.Timeout = 60
@ -177,7 +230,7 @@ func main() {
}
db, _ := gorm.Open(sqlite.Open(viper.GetString("database.dsn")))
db.AutoMigrate(&Watch{}, &URL{}, &Query{})
db.AutoMigrate(&Watch{}, &URL{}, &Query{}, &Filter{})
//bot, _ := tgbotapi.NewBotAPI(viper.GetString("telegram.token"))
@ -199,6 +252,7 @@ func main() {
templates.AddFromFiles("index", "templates/base.html", "templates/index.html")
templates.AddFromFiles("newWatch", "templates/base.html", "templates/newWatch.html")
templates.AddFromFiles("viewWatch", "templates/base.html", "templates/viewWatch.html")
templates.AddFromFiles("editQuery", "templates/base.html", "templates/editQuery.html")
router.HTMLRender = templates
router.GET("/", web.index)
@ -208,6 +262,8 @@ func main() {
router.GET("/watch/view/:id/", web.viewWatch)
router.POST("/url/create/", web.createURL)
router.POST("/query/create/", web.createQuery)
router.GET("/query/edit/:id", web.editQuery)
router.POST("/filter/create/", web.createFilter)
router.Run("0.0.0.0:8080")
}

View file

@ -14,6 +14,7 @@ type Watch struct {
type URL struct {
gorm.Model
WatchID uint
Watch Watch
Name string
URL string
Queries []Query
@ -21,8 +22,20 @@ type URL struct {
type Query struct {
gorm.Model
URLID uint
Name string
Type string
Query string
URLID uint
URL URL
Name string
Type string
Query string
Filters []Filter
}
type Filter struct {
gorm.Model
QueryID uint
Query Query
Name string
Type string
From string
To string
}

94
scraping.go Normal file
View file

@ -0,0 +1,94 @@
package main
import (
"bytes"
"log"
"regexp"
"strconv"
"strings"
"github.com/antchfx/htmlquery"
"golang.org/x/net/html"
)
func getQueryResult(query *Query) []string {
doc, err := htmlquery.LoadURL(query.URL.URL)
if err != nil {
log.Print("Something went wrong loading loading", query.URL.URL)
}
nodes, _ := htmlquery.QueryAll(doc, query.Query)
nodeStrings := make([]string, len(nodes))
for i, node := range nodes {
var b bytes.Buffer
html.Render(&b, node)
nodeStrings[i] = b.String()
}
for _, filter := range query.Filters {
for i, nodeString := range nodeStrings {
nodeStrings[i] = getFilterResult(nodeString, &filter)
}
}
return nodeStrings
}
func getFilterResult(s string, filter *Filter) string {
switch {
case filter.Type == "replace":
{
return getFilterResultReplace(s, filter)
}
case filter.Type == "regex":
{
return getFilterResultRegex(s, filter)
}
case filter.Type == "substring":
{
return getFilterResultSubstring(s, filter)
}
default:
return s
}
}
func getFilterResultReplace(s string, filter *Filter) string {
return strings.ReplaceAll(s, filter.From, filter.To)
}
func getFilterResultRegex(s string, filter *Filter) string {
regex, err := regexp.Compile(filter.From)
if err != nil {
return s
}
return regex.ReplaceAllString(s, filter.To)
}
func getFilterResultSubstring(s string, filter *Filter) string {
substrings := strings.Split(filter.From, ",")
var sb strings.Builder
asRunes := []rune(s)
for _, substring := range substrings {
if strings.Contains(substring, "-") {
from_to := strings.Split(substring, "-")
if len(from_to) != 2 {
return s
}
from, err := strconv.ParseInt(from_to[0], 10, 32)
if err != nil {
return s
}
to, err := strconv.ParseInt(from_to[1], 10, 32)
if err != nil {
return s
}
sb.WriteString(string(asRunes[from:to]))
} else {
pos, err := strconv.ParseInt(substring, 10, 32)
if err != nil {
return s
}
sb.WriteRune(asRunes[pos])
}
}
return sb.String()
}

174
templates/editQuery.html Normal file
View file

@ -0,0 +1,174 @@
{{define "content"}}
<div class="card mb-5">
<div class="card-header text-center text-white bg-dark ">
<div class="h2">{{ .Query.URL.Watch.Name }} - {{ .Query.Name }}</div>
<div class="h6">{{ .Query.URL.URL }}</div>
</div>
<div class="card-header text-white bg-secondary">
<div class="row">
<div class="col-2">{{ .Query.Type }}</div>
<div class="col-8">{{ .Query.Query }}</div>
</div>
</div>
<div class="card-body">
<div class="card mb-2">
<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>
{{ range .Query.Filters }}
<tr>
<td>{{ .Name }}</td>
<td>{{ .Type }}</td>
<td>{{ .From }}</td>
<td>{{ .To }}</td>
<td></td>
</tr>
{{ end }}
<tr>
<td></td>
<td colspan="2">
<div class="row text-center">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#newFilterModal">
Add Filter
</button>
</div>
</td>
<td></td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>
{{ range .currentResult }}
<div class="card">
<div class="card-body">
<div class="card-header text-center text-white bg-dark ">
<div class="h6">Result</div>
</div>
<code>
{{ . }}
</code>
</div>
</div>
{{ end }}
<div class="modal fade" id="newFilterModal" tabindex="-1" aria-labelledby="modalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalLabel">Add Filter</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<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>
</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" >
<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>
<div class="col-sm-10 p-2">
<input type="text" class="form-control" name="from" id="fromInput" placeholder="Something">
</div>
<label for="toInput" class="col-sm-2 col-form-label">To:</label>
<div class="col-sm-10 p-2">
<input type="text" class="form-control" name="to" id="toInput" placeholder="Else">
</div>
<button class="btn btn-primary mt-4">Add Filter</button>
</div>
</form>
</div>
<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" >
<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>
<div class="col-sm-10 p-2">
<input type="text" class="form-control" name="from" id="fromInput" placeholder="So[mM]e(thing|where)">
</div>
<label for="toInput" class="col-sm-2 col-form-label">To:</label>
<div class="col-sm-10 p-2">
<input type="text" class="form-control" name="to" id="toInput" placeholder="Else">
</div>
<button class="btn btn-primary mt-4">Add Filter</button>
</div>
</form>
</div>
<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="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>
<div class="col-sm-10 p-2">
<input type="text" class="form-control" name="from" id="fromInput" placeholder="0-3,4,6,10-13">
</div>
<button class="btn btn-primary mt-4">Add Filter</button>
</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>
</div>
{{ end }}

View file

@ -12,58 +12,90 @@
{{ range .URLs }}
<div class="card mb-5">
<div class="card-header text-center text-white bg-dark ">
<div class="h5">{{ .Name }}</div>
<div class="h3">{{ .Name }} URL</div>
</div>
<div class="card-header bg-secondary text-white text-center">
<div>{{ .URL }}</div>
</div>
<div class="card-body">
<form action="/query/create" method="post">
<table class="table table-hover caption-top">
<thead>
<tr class="table-secondary">
<th scope="col">Name</th>
<th scope="col">Type</th>
<th scope="col">Query</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{{ range .Queries }}
{{ range .Queries }}
<div class="card mb-2">
<div class="card-header">
<div class="row">
<div class="col h5 text-start">{{ .Type }}</div>
<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>
<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>
{{ range .Filters }}
<tr>
<td>{{ .Name }}</td>
<td>{{ .Type }}</td>
<td>{{ .From }}</td>
<td>{{ .To }}</td>
<td></td>
</tr>
{{ end }}
<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>
</tr>
</tbody>
</table>
</form>
</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 }}" >
<table class="table table-hover caption-top">
<tbody>
<tr>
<td>{{ .Name }}</td>
<td>{{ .Type }}</td>
<td>{{ .Query }}</td>
<td>Delete</td>
<td>
<input type="text" class="form-control" name="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>
</td>
<td>
<input type="text" class="form-control" name="query" placeholder="Query">
</td>
<td>
<button class="btn btn-primary">Add Query</button>
</td>
</tr>
{{ end }}
<tr>
<td>
<input type="text" class="form-control" name="name" placeholder="Name">
</td>
<td>
<select class="form-control" id="type" name="type">
<option>CSS Selector</option>
<option>XPath</option>
<option>Regex</option>
<option>JSON</option>
</select>
</td>
<td>
<input type="text" class="form-control" name="query" placeholder="Query">
</td>
<td>
<button class="btn btn-primary">Add Query</button>
</td>
</tr>
</tbody>
</table>
<input type="hidden" name="url_id" value="{{ .ID }}" >
<input type="hidden" name="watch_id" value="{{ $.ID }}" >
</form>
</tbody>
</table>
</form>
</div>
</div>
{{ end }}
@ -74,7 +106,7 @@
<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="Name">
<input type="text" class="form-control" name="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">