notifier fixers - UI fixes

pull/78/head
Hunter Long 2018-09-14 22:07:17 -07:00
parent 8c20efd9cc
commit f096db178f
16 changed files with 127 additions and 43 deletions

View File

@ -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
func OnNewNotifier(n *Notification) {
for _, comm := range AllCommunications {

View File

@ -122,6 +122,12 @@ func (n *Example) OnFailure(s *types.Service, f *types.Failure) {
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
func (n *Example) OnNewService(s *types.Service) {
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)
}
// 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
func (n *Example) OnNewNotifier(s *Notification) {
msg := fmt.Sprintf("received a new notifier trigger for notifier: %v\n", s.Method)

View File

@ -21,7 +21,6 @@ import "github.com/hunterlong/statup/types"
type Notifier interface {
OnSave() 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
}
@ -31,6 +30,11 @@ type BasicEvents interface {
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
type ServiceEvents interface {
OnNewService(*types.Service)
@ -48,6 +52,7 @@ type UserEvents interface {
// CoreEvents are events for the main Core app
type CoreEvents interface {
OnUpdatedCore(*types.Core)
OnStart(*types.Core)
}
// NotifierEvents are events for other Notifiers

View File

@ -57,6 +57,7 @@ type Notification struct {
Delay time.Duration `gorm:"-" json:"-"`
Queue []interface{} `gorm:"-" json:"-"`
Running chan bool `gorm:"-" json:"-"`
CanTest bool `gorm:"-" json:"-"`
}
type NotificationForm struct {
@ -65,6 +66,7 @@ type NotificationForm struct {
Placeholder string
DbField string
SmallText string
Required bool
}
type NotificationLog struct {
@ -299,13 +301,22 @@ func (f *Notification) LastSent() time.Duration {
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 {
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
hourAgo := time.Now().Add(-1 * time.Minute)
for _, v := range f.Logs() {
lastTime := time.Time(v.Time)
if lastTime.After(hourAgo) {
if lastTime.After(since) {
sent++
}
}
@ -340,6 +351,11 @@ func (n *Notification) GetValue(dbField string) string {
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
func isType(n interface{}, obj interface{}) bool {
one := reflect.TypeOf(n)

View File

@ -74,6 +74,7 @@ func TestIsBasicType(t *testing.T) {
assert.True(t, isType(example, new(UserEvents)))
assert.True(t, isType(example, new(CoreEvents)))
assert.True(t, isType(example, new(NotifierEvents)))
assert.True(t, isType(example, new(Tester)))
}
func TestLoad(t *testing.T) {

View File

@ -89,6 +89,29 @@ func InsertSampleData() error {
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 {
core := &types.Core{
Name: "Statup Sample Data",

View File

@ -141,6 +141,9 @@ func ExecuteResponse(w http.ResponseWriter, r *http.Request, file string, data i
"CHART_DATA": func() string {
return ""
},
"Error": func() string {
return ""
},
})
t, err = t.Parse(nav)
if err != nil {

View File

@ -140,6 +140,7 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
if sample == "on" {
core.InsertSampleData()
core.InsertSampleHits()
}
core.InitApp()

View File

@ -70,11 +70,6 @@ func (u *Discord) Send(msg interface{}) error {
return resp.Body.Close()
}
func (u *Discord) Test() error {
u.AddQueue([]byte(DISCORD_TEST))
return nil
}
func (u *Discord) Select() *notifier.Notification {
return u.Notification
}

View File

@ -94,7 +94,7 @@ func (u *Email) Send(msg interface{}) error {
return nil
}
func (u *Email) Test() error {
func (u *Email) OnTest(n notifier.Notification) (bool, error) {
email := &EmailOutgoing{
To: emailer.GetValue("var2"),
Subject: "Test Email",
@ -103,7 +103,7 @@ func (u *Email) Test() error {
From: emailer.GetValue("var1"),
}
u.AddQueue(email)
return nil
return true, nil
}
type EmailOutgoing struct {

View File

@ -75,12 +75,6 @@ func (u *LineNotify) Select() *notifier.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
func (u *LineNotify) OnFailure(s *types.Service, f *types.Failure) {
msg := fmt.Sprintf("Your service '%v' is currently offline!", s.Name)

View File

@ -46,6 +46,7 @@ var slacker = &Slack{&notifier.Notification{
AuthorUrl: "https://github.com/hunterlong",
Delay: time.Duration(10 * time.Second),
Host: "https://webhooksurl.slack.com/***",
CanTest: true,
Form: []notifier.NotificationForm{{
Type: "text",
Title: "Incoming Webhook Url",
@ -94,10 +95,11 @@ func (u *Slack) Select() *notifier.Notification {
return u.Notification
}
func (u *Slack) Test() error {
func (u *Slack) OnTest(n notifier.Notification) (bool, error) {
utils.Log(1, "Slack notifier loaded")
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

View File

@ -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 {
return u.Notification
}

View File

@ -377,6 +377,11 @@ HTML, BODY {
cursor: -moz-grabbing;
cursor: -webkit-grabbing; }
.switch_btn {
float: right;
margin: -1px 0px 0px 0px;
display: block; }
@media (max-width: 767px) {
HTML, BODY {
background-color: #fcfcfc; }

View File

@ -435,4 +435,10 @@ HTML,BODY {
cursor: -webkit-grabbing;
}
@import 'mobile';
.switch_btn {
float: right;
margin: -1px 0px 0px 0px;
display: block;
}
@import 'mobile';

View File

@ -42,6 +42,9 @@
</div>
</div>
<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-pane fade show active" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab">
<h3>Settings</h3>
@ -135,43 +138,59 @@
{{ range .Notifications }}
{{$n := .Select}}
<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 }}">
{{if $n.Title}}<h4>{{$n.Title}}
</h4>{{end}}
{{if $n.Description}}<p class="text-muted">{{safe $n.Description}}</p>{{end}}
{{range .Form}}
<div class="form-group">
<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}}
</div>
{{end}}
<div class="form-group">
<label class="text-capitalize" for="limits_per_hour_{{underscore $n.Method }}">Limits per Hour</label>
<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="row">
<div class="col-sm-6">
<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 class="form-group row">
<div class="col-sm-6">
<span class="switch">
<div class="col-sm-2 mt-1">
<span class="switch">
<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>
</span>
</div>
<div class="col-sm-6">
<button type="submit" class="btn btn-primary btn-block text-capitalize">Save {{ $n.Method }} Settings</button>
<label for="switch-{{ $n.Method }}"></label>
</span>
</div>
<div class="col-sm-4">
<button type="submit" class="btn btn-primary btn-block text-capitalize">Save</button>
</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}}
<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>
</span>
{{ end }}
</form>
{{ 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 }}
<div class="card mt-1">
<div class="card-body">