added 'schedules' page, allowing quick enabling/disabling of schedule filters

This commit is contained in:
BroodjeAap 2023-03-25 17:09:23 +00:00
parent a9790cd64d
commit 9938af6a3b
4 changed files with 142 additions and 16 deletions

View file

@ -3,23 +3,27 @@ package models
import (
"fmt"
"html"
"github.com/robfig/cron/v3"
)
type FilterID uint
type FilterType string
type Filter struct {
ID FilterID `form:"filter_id" yaml:"filter_id" json:"filter_id"`
WatchID WatchID `form:"filter_watch_id" gorm:"index" yaml:"filter_watch_id" json:"filter_watch_id" binding:"required"`
Name string `form:"filter_name" gorm:"index" yaml:"filter_name" json:"filter_name" binding:"required" validate:"min=1"`
X int `form:"x" yaml:"x" json:"x" validate:"default=0"`
Y int `form:"y" yaml:"y" json:"y" validate:"default=0"`
Type FilterType `form:"filter_type" yaml:"filter_type" json:"filter_type" binding:"required" validate:"oneof=url xpath json css replace match substring math store condition cron"`
Var1 string `form:"var1" yaml:"var1" json:"var1" binding:"required"`
Var2 *string `form:"var2" yaml:"var2" json:"var2"`
Parents []*Filter `gorm:"-:all"`
Children []*Filter `gorm:"-:all"`
Results []string `gorm:"-:all"`
Logs []string `gorm:"-:all"`
ID FilterID `form:"filter_id" yaml:"filter_id" json:"filter_id"`
WatchID WatchID `form:"filter_watch_id" gorm:"index" yaml:"filter_watch_id" json:"filter_watch_id" binding:"required"`
Name string `form:"filter_name" gorm:"index" yaml:"filter_name" json:"filter_name" binding:"required" validate:"min=1"`
X int `form:"x" yaml:"x" json:"x" validate:"default=0"`
Y int `form:"y" yaml:"y" json:"y" validate:"default=0"`
Type FilterType `form:"filter_type" yaml:"filter_type" json:"filter_type" binding:"required" validate:"oneof=url xpath json css replace match substring math store condition cron"`
Var1 string `form:"var1" yaml:"var1" json:"var1" binding:"required"`
Var2 *string `form:"var2" yaml:"var2" json:"var2"`
Parents []*Filter `gorm:"-:all"`
Children []*Filter `gorm:"-:all"`
Results []string `gorm:"-:all"`
Logs []string `gorm:"-:all"`
CronEntry *cron.Entry `gorm:"-:all"`
Enabled string `gorm:"-:all"` // lazy fix for not being able to pointer deref in golang template....
}
func (filter *Filter) Log(v ...any) {

View file

@ -18,15 +18,12 @@
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">Go Watch</a>
<a class="navbar-brand" href="{{.urlPrefix}}">Go Watch</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav me-auto mb-2 mb-md-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="{{.urlPrefix}}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" aria-current="page" href="{{.urlPrefix}}notifiers/view">Notifiers</a>
</li>
@ -36,6 +33,9 @@
<li class="nav-item">
<a class="nav-link" aria-current="page" href="{{.urlPrefix}}backup/view">Backups</a>
</li>
<li class="nav-item">
<a class="nav-link" aria-current="page" href="{{.urlPrefix}}schedules/view">Schedules</a>
</li>
{{ template "navbar" .}}
</ul>
<div class="d-flex">

View file

@ -0,0 +1,49 @@
{{define "title"}}
GoWatch
{{end}}
{{define "content"}}
<form action="{{.urlPrefix}}schedules/update" method="POST">
<table class="table table-striped table-hover">
<thead class="table-dark">
<tr>
<th>WatchID</th>
<th>Watch</th>
<th>Schedule</th>
<th>Last</th>
<th>Next</th>
<th>Enabled</th>
</tr>
</thead>
<tbody>
{{ range $watch, $scheduleFilters := .watchSchedules }}
{{ range $i, $scheduleFilter := $scheduleFilters }}
<tr>
<td class="h3">{{ $watch.ID }}</td>
<td class="h3">{{ $watch.Name }}</td>
<td class="h3">{{ $scheduleFilter.Name }}</td>
{{ if $scheduleFilter.CronEntry }}
<td class="h3">{{ $scheduleFilter.CronEntry.Prev.Format "2006-01-02 15:04:05" }}</td>
<td class="h3">{{ $scheduleFilter.CronEntry.Next.Format "2006-01-02 15:04:05" }}</td>
{{ else }}
<td colspan="2" class="h3">Not scheduled</td>
{{ end }}
{{ if eq $scheduleFilter.Enabled "yes" }}
<td class="h2">
<input class="form-check-input" id="schedules_{{ $scheduleFilter.ID }}" type="checkbox" value="{{ $scheduleFilter.ID }}" name="schedules" checked>
</td>
{{ else }}
<td class="h2">
<input class="form-check-input" id="schedules_{{ $scheduleFilter.ID }}" type="checkbox" value="{{ $scheduleFilter.ID }}" name="schedules">
</td>
{{ end}}
</tr>
{{ end }}
{{ end }}
</tbody>
</table>
<div class="text-center">
<button type="submit" class="btn btn-primary btn-lg">Update</button>
</div>
</form>
{{end}}

View file

@ -227,6 +227,9 @@ func (web *Web) initRouter() {
gowatch.GET("notifiers/view", web.notifiersView)
gowatch.POST("notifiers/test", web.notifiersTest)
gowatch.GET("schedules/view", web.schedulesView)
gowatch.POST("schedules/update", web.schedulesUpdate)
gowatch.GET("backup/view", web.backupView)
gowatch.GET("backup/create", web.backupCreate)
gowatch.POST("backup/test", web.backupTest)
@ -256,6 +259,8 @@ func (web *Web) initTemplates() {
web.templates.Add("notifiersView", template.Must(template.ParseFS(templatesFS, "base.html", "notifiers.html")))
web.templates.Add("schedulesView", template.Must(template.ParseFS(templatesFS, "base.html", "schedules.html")))
web.templates.Add("backupView", template.Must(template.ParseFS(templatesFS, "base.html", "backup/view.html")))
web.templates.Add("backupTest", template.Must(template.ParseFS(templatesFS, "base.html", "backup/test.html")))
web.templates.Add("backupRestore", template.Must(template.ParseFS(templatesFS, "base.html", "backup/restore.html")))
@ -513,6 +518,74 @@ func (web *Web) notifiersTest(c *gin.Context) {
c.Redirect(http.StatusSeeOther, web.urlPrefix+"notifiers/view")
}
func (web *Web) schedulesView(c *gin.Context) {
watches := []Watch{}
web.db.Find(&watches)
watchMap := make(map[WatchID]*Watch, len(watches))
for i := 0; i < len(watches); i++ {
watchMap[watches[i].ID] = &watches[i]
}
var filters []Filter
web.db.Model(&Filter{}).Find(&filters, "type = 'cron'")
watchSchedules := make(map[*Watch][]*Filter)
for i := range filters {
filter := &filters[i]
entryID, exists := web.cronWatch[filter.ID]
if exists {
entry := web.cron.Entry(entryID)
filter.CronEntry = &entry
}
filter.Enabled = *filter.Var2
watch := watchMap[filter.WatchID]
watchSchedules[watch] = append(watchSchedules[watch], filter)
}
c.HTML(http.StatusOK, "schedulesView", gin.H{
"watchSchedules": watchSchedules,
"urlPrefix": web.urlPrefix,
})
}
func (web *Web) schedulesUpdate(c *gin.Context) {
scheduleStrings := c.PostFormArray("schedules")
scheduleIDs := make(map[FilterID]bool)
for _, scheduleString := range scheduleStrings {
scheduleID, err := strconv.Atoi(scheduleString)
if err != nil {
continue
}
scheduleIDs[FilterID(scheduleID)] = true
}
var cronFilters []Filter
web.db.Model(&Filter{}).Where("type = 'cron'").Find(&cronFilters)
for i := range cronFilters {
cronFilter := &cronFilters[i]
entryID, exist := web.cronWatch[cronFilter.ID]
_, checked := scheduleIDs[cronFilter.ID]
if exist && !checked {
web.cron.Remove(entryID)
delete(web.cronWatch, cronFilter.ID)
} else if !exist && checked {
yes := "yes"
cronFilter.Var2 = &yes
web.addCronJobIfCronFilter(cronFilter, false)
}
}
if len(scheduleStrings) > 0 {
web.db.Model(&Filter{}).Where("ID IN ?", scheduleStrings).Update("Var2", "yes")
web.db.Model(&Filter{}).Where("ID NOT IN ?", scheduleStrings).Update("Var2", "no")
} else {
web.db.Model(&Filter{}).Where("TRUE").Update("Var2", "no")
}
c.Redirect(http.StatusSeeOther, web.urlPrefix+"schedules/view")
}
// watchCreate (/watch/create) allows user to create a new watch
// A name and an optional template can be picked
func (web *Web) watchCreate(c *gin.Context) {