mirror of https://github.com/statping/statping
notifier fixers - UI fixes
parent
8c20efd9cc
commit
f096db178f
|
@ -110,6 +110,15 @@ func OnUpdatedCore(c *types.Core) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnUpdatedCore is triggered when the CoreApp settings are saved - CoreEvents interface
|
||||||
|
func OnStart(c *types.Core) {
|
||||||
|
for _, comm := range AllCommunications {
|
||||||
|
if isType(comm, new(CoreEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||||
|
comm.(CoreEvents).OnUpdatedCore(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NotifierEvents interface
|
// NotifierEvents interface
|
||||||
func OnNewNotifier(n *Notification) {
|
func OnNewNotifier(n *Notification) {
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range AllCommunications {
|
||||||
|
|
|
@ -122,6 +122,12 @@ func (n *Example) OnFailure(s *types.Service, f *types.Failure) {
|
||||||
n.AddQueue(msg)
|
n.AddQueue(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OPTIONAL Test function before user saves
|
||||||
|
func (n *Example) OnTest(s Notification) (bool, error) {
|
||||||
|
fmt.Printf("received a test trigger with form data: %v\n", s.Host)
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// OPTIONAL
|
// OPTIONAL
|
||||||
func (n *Example) OnNewService(s *types.Service) {
|
func (n *Example) OnNewService(s *types.Service) {
|
||||||
msg := fmt.Sprintf("received a new service trigger for service: %v\n", s.Name)
|
msg := fmt.Sprintf("received a new service trigger for service: %v\n", s.Name)
|
||||||
|
@ -164,6 +170,12 @@ func (n *Example) OnUpdatedCore(s *types.Core) {
|
||||||
n.AddQueue(msg)
|
n.AddQueue(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OPTIONAL
|
||||||
|
func (n *Example) OnStart(s *types.Core) {
|
||||||
|
msg := fmt.Sprintf("received a trigger on Statup boot: %v\n", s.Name)
|
||||||
|
n.AddQueue(msg)
|
||||||
|
}
|
||||||
|
|
||||||
// OPTIONAL
|
// OPTIONAL
|
||||||
func (n *Example) OnNewNotifier(s *Notification) {
|
func (n *Example) OnNewNotifier(s *Notification) {
|
||||||
msg := fmt.Sprintf("received a new notifier trigger for notifier: %v\n", s.Method)
|
msg := fmt.Sprintf("received a new notifier trigger for notifier: %v\n", s.Method)
|
||||||
|
|
|
@ -21,7 +21,6 @@ import "github.com/hunterlong/statup/types"
|
||||||
type Notifier interface {
|
type Notifier interface {
|
||||||
OnSave() error // OnSave is triggered when the notifier is saved
|
OnSave() error // OnSave is triggered when the notifier is saved
|
||||||
Send(interface{}) error // OnSave is triggered when the notifier is saved
|
Send(interface{}) error // OnSave is triggered when the notifier is saved
|
||||||
Test() error // Test will run a function inside the notifier to Test if it works
|
|
||||||
Select() *Notification // Select returns the *Notification for a notifier
|
Select() *Notification // Select returns the *Notification for a notifier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +30,11 @@ type BasicEvents interface {
|
||||||
OnFailure(*types.Service, *types.Failure) // OnFailure is triggered when a service is failing
|
OnFailure(*types.Service, *types.Failure) // OnFailure is triggered when a service is failing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tester interface will include a function to Test users settings before saving
|
||||||
|
type Tester interface {
|
||||||
|
OnTest(Notification) (bool, error)
|
||||||
|
}
|
||||||
|
|
||||||
// ServiceEvents are events for Services
|
// ServiceEvents are events for Services
|
||||||
type ServiceEvents interface {
|
type ServiceEvents interface {
|
||||||
OnNewService(*types.Service)
|
OnNewService(*types.Service)
|
||||||
|
@ -48,6 +52,7 @@ type UserEvents interface {
|
||||||
// CoreEvents are events for the main Core app
|
// CoreEvents are events for the main Core app
|
||||||
type CoreEvents interface {
|
type CoreEvents interface {
|
||||||
OnUpdatedCore(*types.Core)
|
OnUpdatedCore(*types.Core)
|
||||||
|
OnStart(*types.Core)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifierEvents are events for other Notifiers
|
// NotifierEvents are events for other Notifiers
|
||||||
|
|
|
@ -57,6 +57,7 @@ type Notification struct {
|
||||||
Delay time.Duration `gorm:"-" json:"-"`
|
Delay time.Duration `gorm:"-" json:"-"`
|
||||||
Queue []interface{} `gorm:"-" json:"-"`
|
Queue []interface{} `gorm:"-" json:"-"`
|
||||||
Running chan bool `gorm:"-" json:"-"`
|
Running chan bool `gorm:"-" json:"-"`
|
||||||
|
CanTest bool `gorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotificationForm struct {
|
type NotificationForm struct {
|
||||||
|
@ -65,6 +66,7 @@ type NotificationForm struct {
|
||||||
Placeholder string
|
Placeholder string
|
||||||
DbField string
|
DbField string
|
||||||
SmallText string
|
SmallText string
|
||||||
|
Required bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type NotificationLog struct {
|
type NotificationLog struct {
|
||||||
|
@ -299,13 +301,22 @@ func (f *Notification) LastSent() time.Duration {
|
||||||
return since
|
return since
|
||||||
}
|
}
|
||||||
|
|
||||||
// SentLastHour returns the amount of sent notifications within the last hour
|
func (f *Notification) SentLastHour() int {
|
||||||
|
since := time.Now().Add(-1 * time.Hour)
|
||||||
|
return f.SentLast(since)
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Notification) SentLastMinute() int {
|
func (f *Notification) SentLastMinute() int {
|
||||||
|
since := time.Now().Add(-1 * time.Minute)
|
||||||
|
return f.SentLast(since)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SentLastHour returns the amount of sent notifications within the last hour
|
||||||
|
func (f *Notification) SentLast(since time.Time) int {
|
||||||
sent := 0
|
sent := 0
|
||||||
hourAgo := time.Now().Add(-1 * time.Minute)
|
|
||||||
for _, v := range f.Logs() {
|
for _, v := range f.Logs() {
|
||||||
lastTime := time.Time(v.Time)
|
lastTime := time.Time(v.Time)
|
||||||
if lastTime.After(hourAgo) {
|
if lastTime.After(since) {
|
||||||
sent++
|
sent++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,6 +351,11 @@ func (n *Notification) GetValue(dbField string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testable returns true if it includes the CoreEvents interface
|
||||||
|
func (n *Notification) Testable() bool {
|
||||||
|
return isType(n, new(Tester))
|
||||||
|
}
|
||||||
|
|
||||||
// isType will return true if a variable can implement an interface
|
// isType will return true if a variable can implement an interface
|
||||||
func isType(n interface{}, obj interface{}) bool {
|
func isType(n interface{}, obj interface{}) bool {
|
||||||
one := reflect.TypeOf(n)
|
one := reflect.TypeOf(n)
|
||||||
|
|
|
@ -74,6 +74,7 @@ func TestIsBasicType(t *testing.T) {
|
||||||
assert.True(t, isType(example, new(UserEvents)))
|
assert.True(t, isType(example, new(UserEvents)))
|
||||||
assert.True(t, isType(example, new(CoreEvents)))
|
assert.True(t, isType(example, new(CoreEvents)))
|
||||||
assert.True(t, isType(example, new(NotifierEvents)))
|
assert.True(t, isType(example, new(NotifierEvents)))
|
||||||
|
assert.True(t, isType(example, new(Tester)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoad(t *testing.T) {
|
func TestLoad(t *testing.T) {
|
||||||
|
|
|
@ -89,6 +89,29 @@ func InsertSampleData() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InsertSampleHits will create a couple new hits for the sample services
|
||||||
|
func InsertSampleHits() error {
|
||||||
|
since := time.Now().Add(-24 * time.Hour)
|
||||||
|
for i := int64(1); i <= 5; i++ {
|
||||||
|
service := SelectService(i)
|
||||||
|
utils.Log(1, fmt.Sprintf("Adding %v sample hit records to service %v", 360, service.Name))
|
||||||
|
createdAt := since
|
||||||
|
|
||||||
|
for hi := int64(1); hi <= 360; hi++ {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
latency := rand.Float64()
|
||||||
|
createdAt = createdAt.Add(2 * time.Minute)
|
||||||
|
hit := &types.Hit{
|
||||||
|
Service: service.Id,
|
||||||
|
CreatedAt: createdAt,
|
||||||
|
Latency: latency,
|
||||||
|
}
|
||||||
|
service.CreateHit(hit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func InsertSampleCore() error {
|
func InsertSampleCore() error {
|
||||||
core := &types.Core{
|
core := &types.Core{
|
||||||
Name: "Statup Sample Data",
|
Name: "Statup Sample Data",
|
||||||
|
|
|
@ -141,6 +141,9 @@ func ExecuteResponse(w http.ResponseWriter, r *http.Request, file string, data i
|
||||||
"CHART_DATA": func() string {
|
"CHART_DATA": func() string {
|
||||||
return ""
|
return ""
|
||||||
},
|
},
|
||||||
|
"Error": func() string {
|
||||||
|
return ""
|
||||||
|
},
|
||||||
})
|
})
|
||||||
t, err = t.Parse(nav)
|
t, err = t.Parse(nav)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -140,6 +140,7 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if sample == "on" {
|
if sample == "on" {
|
||||||
core.InsertSampleData()
|
core.InsertSampleData()
|
||||||
|
core.InsertSampleHits()
|
||||||
}
|
}
|
||||||
|
|
||||||
core.InitApp()
|
core.InitApp()
|
||||||
|
|
|
@ -70,11 +70,6 @@ func (u *Discord) Send(msg interface{}) error {
|
||||||
return resp.Body.Close()
|
return resp.Body.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Discord) Test() error {
|
|
||||||
u.AddQueue([]byte(DISCORD_TEST))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *Discord) Select() *notifier.Notification {
|
func (u *Discord) Select() *notifier.Notification {
|
||||||
return u.Notification
|
return u.Notification
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ func (u *Email) Send(msg interface{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Email) Test() error {
|
func (u *Email) OnTest(n notifier.Notification) (bool, error) {
|
||||||
email := &EmailOutgoing{
|
email := &EmailOutgoing{
|
||||||
To: emailer.GetValue("var2"),
|
To: emailer.GetValue("var2"),
|
||||||
Subject: "Test Email",
|
Subject: "Test Email",
|
||||||
|
@ -103,7 +103,7 @@ func (u *Email) Test() error {
|
||||||
From: emailer.GetValue("var1"),
|
From: emailer.GetValue("var1"),
|
||||||
}
|
}
|
||||||
u.AddQueue(email)
|
u.AddQueue(email)
|
||||||
return nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmailOutgoing struct {
|
type EmailOutgoing struct {
|
||||||
|
|
|
@ -75,12 +75,6 @@ func (u *LineNotify) Select() *notifier.Notification {
|
||||||
return u.Notification
|
return u.Notification
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *LineNotify) Test() error {
|
|
||||||
msg := fmt.Sprintf("You're Statup Line Notify Notifier is working correctly!")
|
|
||||||
u.AddQueue(msg)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
|
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
|
||||||
func (u *LineNotify) OnFailure(s *types.Service, f *types.Failure) {
|
func (u *LineNotify) OnFailure(s *types.Service, f *types.Failure) {
|
||||||
msg := fmt.Sprintf("Your service '%v' is currently offline!", s.Name)
|
msg := fmt.Sprintf("Your service '%v' is currently offline!", s.Name)
|
||||||
|
|
|
@ -46,6 +46,7 @@ var slacker = &Slack{¬ifier.Notification{
|
||||||
AuthorUrl: "https://github.com/hunterlong",
|
AuthorUrl: "https://github.com/hunterlong",
|
||||||
Delay: time.Duration(10 * time.Second),
|
Delay: time.Duration(10 * time.Second),
|
||||||
Host: "https://webhooksurl.slack.com/***",
|
Host: "https://webhooksurl.slack.com/***",
|
||||||
|
CanTest: true,
|
||||||
Form: []notifier.NotificationForm{{
|
Form: []notifier.NotificationForm{{
|
||||||
Type: "text",
|
Type: "text",
|
||||||
Title: "Incoming Webhook Url",
|
Title: "Incoming Webhook Url",
|
||||||
|
@ -94,10 +95,11 @@ func (u *Slack) Select() *notifier.Notification {
|
||||||
return u.Notification
|
return u.Notification
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Slack) Test() error {
|
func (u *Slack) OnTest(n notifier.Notification) (bool, error) {
|
||||||
utils.Log(1, "Slack notifier loaded")
|
utils.Log(1, "Slack notifier loaded")
|
||||||
msg := fmt.Sprintf("You're Statup Slack Notifier is working correctly!")
|
msg := fmt.Sprintf("You're Statup Slack Notifier is working correctly!")
|
||||||
return sendSlack(TEST_TEMPLATE, msg)
|
err := sendSlack(TEST_TEMPLATE, msg)
|
||||||
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
|
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
|
||||||
|
|
|
@ -77,13 +77,6 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Twilio) Test() error {
|
|
||||||
utils.Log(1, "Twilio notifier loaded")
|
|
||||||
msg := fmt.Sprintf("You're Statup Twilio Notifier is working correctly!")
|
|
||||||
u.AddQueue(msg)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *Twilio) Select() *notifier.Notification {
|
func (u *Twilio) Select() *notifier.Notification {
|
||||||
return u.Notification
|
return u.Notification
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,6 +377,11 @@ HTML, BODY {
|
||||||
cursor: -moz-grabbing;
|
cursor: -moz-grabbing;
|
||||||
cursor: -webkit-grabbing; }
|
cursor: -webkit-grabbing; }
|
||||||
|
|
||||||
|
.switch_btn {
|
||||||
|
float: right;
|
||||||
|
margin: -1px 0px 0px 0px;
|
||||||
|
display: block; }
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
HTML, BODY {
|
HTML, BODY {
|
||||||
background-color: #fcfcfc; }
|
background-color: #fcfcfc; }
|
||||||
|
|
|
@ -435,4 +435,10 @@ HTML,BODY {
|
||||||
cursor: -webkit-grabbing;
|
cursor: -webkit-grabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
@import 'mobile';
|
.switch_btn {
|
||||||
|
float: right;
|
||||||
|
margin: -1px 0px 0px 0px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@import 'mobile';
|
||||||
|
|
|
@ -42,6 +42,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8 col-sm-12">
|
<div class="col-md-8 col-sm-12">
|
||||||
|
{{if Error}}
|
||||||
|
<div class="alert alert-danger" role="alert">{{Error}}</div>
|
||||||
|
{{end}}
|
||||||
<div class="tab-content" id="v-pills-tabContent">
|
<div class="tab-content" id="v-pills-tabContent">
|
||||||
<div class="tab-pane fade show active" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab">
|
<div class="tab-pane fade show active" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab">
|
||||||
<h3>Settings</h3>
|
<h3>Settings</h3>
|
||||||
|
@ -135,43 +138,59 @@
|
||||||
{{ range .Notifications }}
|
{{ range .Notifications }}
|
||||||
{{$n := .Select}}
|
{{$n := .Select}}
|
||||||
<div class="tab-pane" id="v-pills-{{underscore $n.Method}}" role="tabpanel" aria-labelledby="v-pills-{{underscore $n.Method }}-tab">
|
<div class="tab-pane" id="v-pills-{{underscore $n.Method}}" role="tabpanel" aria-labelledby="v-pills-{{underscore $n.Method }}-tab">
|
||||||
{{if $n.Title}}<h4>{{$n.Title}}</h4>{{end}}
|
|
||||||
{{if $n.Description}}<p class="text-muted">{{safe $n.Description}}</p>{{end}}
|
|
||||||
<form method="POST" action="/settings/notifier/{{ $n.Method }}">
|
<form method="POST" action="/settings/notifier/{{ $n.Method }}">
|
||||||
|
{{if $n.Title}}<h4>{{$n.Title}}
|
||||||
|
</h4>{{end}}
|
||||||
|
{{if $n.Description}}<p class="text-muted">{{safe $n.Description}}</p>{{end}}
|
||||||
{{range .Form}}
|
{{range .Form}}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="text-capitalize" for="{{underscore .Title}}">{{.Title}}</label>
|
<label class="text-capitalize" for="{{underscore .Title}}">{{.Title}}</label>
|
||||||
<input type="{{.Type}}" name="{{underscore .DbField}}" class="form-control" value="{{ $n.GetValue .DbField }}" id="{{underscore .Title}}" placeholder="{{.Placeholder}}">
|
<input type="{{.Type}}" name="{{underscore .DbField}}" class="form-control" value="{{ $n.GetValue .DbField }}" id="{{underscore .Title}}" placeholder="{{.Placeholder}}" {{if .Required}}required{{end}}>
|
||||||
{{if .SmallText}}<small class="form-text text-muted">{{safe .SmallText}}</small>{{end}}
|
{{if .SmallText}}<small class="form-text text-muted">{{safe .SmallText}}</small>{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="row">
|
||||||
<label class="text-capitalize" for="limits_per_hour_{{underscore $n.Method }}">Limits per Hour</label>
|
<div class="col-sm-6">
|
||||||
<input type="number" name="limits" class="form-control" value="{{$n.Limits}}" id="limits_per_hour_{{underscore $n.Method }}" min="1" max="60" placeholder="How many messages can send per hour">
|
<div class="input-group mb-2">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<div class="input-group-text">Limit</div>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-control" name="limits" min="1" max="60" id="limits_per_hour_{{underscore $n.Method }}" value="{{$n.Limits}}" placeholder="7">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<div class="input-group-text">Per Minute</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group row">
|
<div class="col-sm-2 mt-1">
|
||||||
<div class="col-sm-6">
|
<span class="switch">
|
||||||
<span class="switch">
|
|
||||||
<input type="checkbox" name="enable" class="switch" id="switch-{{ $n.Method }}" {{if $n.Enabled}}checked{{end}}>
|
<input type="checkbox" name="enable" class="switch" id="switch-{{ $n.Method }}" {{if $n.Enabled}}checked{{end}}>
|
||||||
<label for="switch-{{ $n.Method }}">Enable {{ $n.Method }}</label>
|
<label for="switch-{{ $n.Method }}"></label>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<button type="submit" class="btn btn-primary btn-block text-capitalize">Save {{ $n.Method }} Settings</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<button type="submit" class="btn btn-primary btn-block text-capitalize">Save</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{if $n.CanTest}}
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<button class="btn btn-secondary btn-block text-capitalize">Test</button>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
{{if $n.Author}}
|
{{if $n.Author}}
|
||||||
<span class="d-block small text-center">
|
<span class="d-block small text-center mt-3 mb-5">
|
||||||
{{$n.Title}} Notifier created by <a href="{{$n.AuthorUrl}}" target="_blank">{{$n.Author}}</a>
|
{{$n.Title}} Notifier created by <a href="{{$n.AuthorUrl}}" target="_blank">{{$n.Author}}</a>
|
||||||
</span>
|
</span>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{{ if $n.Logs }}
|
{{ if $n.Logs }}
|
||||||
Sent {{$n.SentLastHour}} out of {{$n.Limit}} in the last hour<br>
|
Sent {{$n.SentLastHour}} in the last hour<br>
|
||||||
{{ range $n.Logs }}
|
{{ range $n.Logs }}
|
||||||
<div class="card mt-1">
|
<div class="card mt-1">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
Loading…
Reference in New Issue