mirror of https://github.com/statping/statping
Merge pull request #682 from statping/notifier-updates-fixes
Notifier Updates and UI Fixespull/687/head
commit
89ba7a6359
|
@ -135,6 +135,7 @@ jobs:
|
||||||
TWILIO_SECRET: ${{ secrets.TWILIO_SECRET }}
|
TWILIO_SECRET: ${{ secrets.TWILIO_SECRET }}
|
||||||
TWILIO_FROM: ${{ secrets.TWILIO_FROM }}
|
TWILIO_FROM: ${{ secrets.TWILIO_FROM }}
|
||||||
TWILIO_TO: ${{ secrets.TWILIO_TO }}
|
TWILIO_TO: ${{ secrets.TWILIO_TO }}
|
||||||
|
TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
|
||||||
|
|
||||||
- name: Coveralls Testing Coverage
|
- name: Coveralls Testing Coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -135,6 +135,7 @@ jobs:
|
||||||
TWILIO_SECRET: ${{ secrets.TWILIO_SECRET }}
|
TWILIO_SECRET: ${{ secrets.TWILIO_SECRET }}
|
||||||
TWILIO_FROM: ${{ secrets.TWILIO_FROM }}
|
TWILIO_FROM: ${{ secrets.TWILIO_FROM }}
|
||||||
TWILIO_TO: ${{ secrets.TWILIO_TO }}
|
TWILIO_TO: ${{ secrets.TWILIO_TO }}
|
||||||
|
TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
|
||||||
|
|
||||||
- name: Coveralls Testing Coverage
|
- name: Coveralls Testing Coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# 0.90.55 (06-18-2020)
|
# 0.90.55 (06-18-2020)
|
||||||
- Added 404 page
|
- Added 404 page
|
||||||
- Modified Statping's PR process, dev -> master
|
- Modified Statping's PR process, dev -> master
|
||||||
|
- Fixed Discord notifier
|
||||||
|
- Modified email template for SMTP emails
|
||||||
|
- Added OnSave() method for all notifiers
|
||||||
|
|
||||||
# 0.90.54 (06-17-2020)
|
# 0.90.54 (06-17-2020)
|
||||||
- Fixed Slack Notifier's failure/success data saving issue
|
- Fixed Slack Notifier's failure/success data saving issue
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
{{$t('dashboard.wrong_login')}}
|
{{$t('dashboard.wrong_login')}}
|
||||||
</div>
|
</div>
|
||||||
<button @click.prevent="login" type="submit" class="btn btn-block mb-3 btn-primary" :disabled="disabled || loading">
|
<button @click.prevent="login" type="submit" class="btn btn-block mb-3 btn-primary" :disabled="disabled || loading">
|
||||||
{{loading ? $t('dashboard.loading') : $t('dashboard.sign_in')}}
|
<font-awesome-icon v-if="loading" icon="circle-notch" class="mr-2" spin/>{{loading ? $t('dashboard.loading') : $t('dashboard.sign_in')}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -89,12 +89,12 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4 col-md-4">
|
<div class="col-4 col-md-4">
|
||||||
<button @click.prevent="testNotifier('success')" class="btn btn-outline-dark btn-block text-capitalize test-notifier">
|
<button @click.prevent="testNotifier('success')" :disabled="loadingTest" class="btn btn-outline-dark btn-block text-capitalize test-notifier">
|
||||||
<i class="fa fa-vial"></i>{{loadingTest ? "Loading..." : "Test Success"}}</button>
|
<font-awesome-icon v-if="loadingTest" icon="circle-notch" class="mr-2" spin/>{{loadingTest ? "Loading..." : "Test Success"}}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4 col-md-4">
|
<div class="col-4 col-md-4">
|
||||||
<button @click.prevent="testNotifier('failure')" class="btn btn-outline-dark btn-block text-capitalize test-notifier">
|
<button @click.prevent="testNotifier('failure')" :disabled="loadingTest" class="btn btn-outline-dark btn-block text-capitalize test-notifier">
|
||||||
<i class="fa fa-vial"></i>{{loadingTest ? "Loading..." : "Test Failure"}}</button>
|
<font-awesome-icon v-if="loadingTest" icon="circle-notch" class="mr-2" spin/>{{loadingTest ? "Loading..." : "Test Failure"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,6 @@
|
||||||
return {
|
return {
|
||||||
tab: "v-pills-home-tab",
|
tab: "v-pills-home-tab",
|
||||||
qrcode: "",
|
qrcode: "",
|
||||||
qrurl: "",
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -174,8 +173,8 @@
|
||||||
const n = await Api.notifiers()
|
const n = await Api.notifiers()
|
||||||
this.$store.commit('setNotifiers', n)
|
this.$store.commit('setNotifiers', n)
|
||||||
|
|
||||||
this.qrurl = `statping://setup?domain=${c.domain}&api=${c.api_secret}`
|
const u = `statping://setup?domain=${c.domain}&api=${c.api_secret}`
|
||||||
this.qrcode = "https://chart.googleapis.com/chart?chs=500x500&cht=qr&chl=" + encodeURI(this.qrurl)
|
this.qrcode = "https://chart.googleapis.com/chart?chs=500x500&cht=qr&chl=" + encodeURIComponent(u)
|
||||||
this.cache = await Api.cache()
|
this.cache = await Api.cache()
|
||||||
},
|
},
|
||||||
changeTab(e) {
|
changeTab(e) {
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -15,6 +15,7 @@ require (
|
||||||
github.com/golang/protobuf v1.3.5 // indirect
|
github.com/golang/protobuf v1.3.5 // indirect
|
||||||
github.com/gorilla/mux v1.7.4
|
github.com/gorilla/mux v1.7.4
|
||||||
github.com/gorilla/securecookie v1.1.1
|
github.com/gorilla/securecookie v1.1.1
|
||||||
|
github.com/hako/durafmt v0.0.0-20200605151348-3a43fc422dd9
|
||||||
github.com/jinzhu/gorm v1.9.12
|
github.com/jinzhu/gorm v1.9.12
|
||||||
github.com/magiconair/properties v1.8.1
|
github.com/magiconair/properties v1.8.1
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -129,6 +129,8 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/hako/durafmt v0.0.0-20200605151348-3a43fc422dd9 h1:IEhIezS5kcD4ZzOwVl8dAyJ9JCi4Xo6tg44Vj/z7UsI=
|
||||||
|
github.com/hako/durafmt v0.0.0-20200605151348-3a43fc422dd9/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE=
|
||||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
|
|
@ -248,8 +248,6 @@ func TestMainApiRoutes(t *testing.T) {
|
||||||
ExpectedContains: []string{
|
ExpectedContains: []string{
|
||||||
`go_goroutines`,
|
`go_goroutines`,
|
||||||
`go_memstats_alloc_bytes`,
|
`go_memstats_alloc_bytes`,
|
||||||
`process_cpu_seconds_total`,
|
|
||||||
`promhttp_metric_handler_requests_total`,
|
|
||||||
`go_threads`,
|
`go_threads`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -53,7 +53,13 @@ func apiNotifierUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(err, w, r)
|
sendErrorJson(err, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//notifications.OnSave(notifer.Method)
|
|
||||||
|
notif := services.ReturnNotifier(notifer.Method)
|
||||||
|
if _, err := notif.OnSave(); err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
sendJsonAction(vars["notifier"], "update", w, r)
|
sendJsonAction(vars["notifier"], "update", w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,3 +70,8 @@ func (c *commandLine) OnTest() (string, error) {
|
||||||
utils.Log.Infoln(out)
|
utils.Log.Infoln(out)
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (c *commandLine) OnSave() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
|
@ -52,15 +52,13 @@ func (d *discord) Select() *notifications.Notification {
|
||||||
|
|
||||||
// OnFailure will trigger failing service
|
// OnFailure will trigger failing service
|
||||||
func (d *discord) OnFailure(s *services.Service, f *failures.Failure) (string, error) {
|
func (d *discord) OnFailure(s *services.Service, f *failures.Failure) (string, error) {
|
||||||
msg := `{"content": "Your service '{{.Service.Name}}' is currently failing! Reason: {{.Failure.Issue}}"}`
|
out, err := d.sendRequest(ReplaceVars(d.FailureData, s, f))
|
||||||
out, err := d.sendRequest(ReplaceVars(msg, s, f))
|
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnSuccess will trigger successful service
|
// OnSuccess will trigger successful service
|
||||||
func (d *discord) OnSuccess(s *services.Service) (string, error) {
|
func (d *discord) OnSuccess(s *services.Service) (string, error) {
|
||||||
msg := `{"content": "Your service '{{.Service.Name}}' is currently online!"}`
|
out, err := d.sendRequest(ReplaceVars(d.SuccessData, s, nil))
|
||||||
out, err := d.sendRequest(ReplaceVars(msg, s, nil))
|
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +81,11 @@ func (d *discord) OnTest() (string, error) {
|
||||||
return string(contents), nil
|
return string(contents), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (d *discord) OnSave() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
type discordTestJson struct {
|
type discordTestJson struct {
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
|
|
|
@ -1,96 +1,21 @@
|
||||||
package notifiers
|
package notifiers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-mail/mail"
|
"github.com/go-mail/mail"
|
||||||
|
"github.com/statping/statping/types/core"
|
||||||
"github.com/statping/statping/types/failures"
|
"github.com/statping/statping/types/failures"
|
||||||
"github.com/statping/statping/types/notifications"
|
"github.com/statping/statping/types/notifications"
|
||||||
"github.com/statping/statping/types/notifier"
|
"github.com/statping/statping/types/notifier"
|
||||||
"github.com/statping/statping/types/null"
|
|
||||||
"github.com/statping/statping/types/services"
|
"github.com/statping/statping/types/services"
|
||||||
"github.com/statping/statping/utils"
|
"github.com/statping/statping/utils"
|
||||||
"time"
|
"html/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ notifier.Notifier = (*emailer)(nil)
|
var _ notifier.Notifier = (*emailer)(nil)
|
||||||
|
|
||||||
const (
|
|
||||||
mainEmailTemplate = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml">
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
||||||
<title>Statping email</title>
|
|
||||||
</head>
|
|
||||||
<body style="-webkit-text-size-adjust: none; box-sizing: border-box; color: #74787E; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; height: 100%; line-height: 1.4; margin: 0; width: 100% !important;" bgcolor="#F2F4F6">
|
|
||||||
<style type="text/css">
|
|
||||||
body {
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
line-height: 1.4;
|
|
||||||
background-color: #F2F4F6;
|
|
||||||
color: #74787E;
|
|
||||||
-webkit-text-size-adjust: none;
|
|
||||||
}
|
|
||||||
@media only screen and (max-width: 600px) {
|
|
||||||
.email-body_inner {
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
.email-footer {
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 500px) {
|
|
||||||
.button {
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; margin: 0; padding: 0; width: 100%;" bgcolor="#F2F4F6">
|
|
||||||
<tr>
|
|
||||||
<td align="center" style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; word-break: break-word;">
|
|
||||||
<table class="email-content" width="100%" cellpadding="0" cellspacing="0" style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; margin: 0; padding: 0; width: 100%;">
|
|
||||||
<tr>
|
|
||||||
<td class="email-body" width="100%" cellpadding="0" cellspacing="0" style="-premailer-cellpadding: 0; -premailer-cellspacing: 0; border-bottom-color: #EDEFF2; border-bottom-style: solid; border-bottom-width: 1px; border-top-color: #EDEFF2; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; margin: 0; padding: 0; width: 100%; word-break: break-word;" bgcolor="#FFFFFF">
|
|
||||||
<table class="email-body_inner" align="center" width="570" cellpadding="0" cellspacing="0" style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; margin: 0 auto; padding: 0; width: 570px;" bgcolor="#FFFFFF">
|
|
||||||
<tr>
|
|
||||||
<td class="content-cell" style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; padding: 35px; word-break: break-word;">
|
|
||||||
<h1 style="box-sizing: border-box; color: #2F3133; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 19px; font-weight: bold; margin-top: 0;" align="left">
|
|
||||||
{{ .Service.Name }} is {{ if .Service.Online }}Online{{else}}Offline{{end}}!
|
|
||||||
</h1>
|
|
||||||
<p style="box-sizing: border-box; color: #74787E; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 16px; line-height: 1.5em; margin-top: 0;" align="left">
|
|
||||||
|
|
||||||
{{ if .Service.Online }}
|
|
||||||
Your Statping service <a target="_blank" href="{{.Service.Domain}}">{{.Service.Name}}</a> is back online. This service has been triggered with a HTTP status code of '{{.Service.LastStatusCode}}' and is currently online based on your requirements. Your service was reported online at {{.Service.CreatedAt}}. </p>
|
|
||||||
{{ else }}
|
|
||||||
Your Statping service <a target="_blank" href="{{.Service.Domain}}">{{.Service.Name}}</a> has been triggered with a HTTP status code of '{{.Service.LastStatusCode}}' and is currently offline based on your requirements. This failure was created on {{.Service.CreatedAt}}. </p>
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{if .Service.LastResponse }}
|
|
||||||
<h1 style="box-sizing: border-box; color: #2F3133; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 19px; font-weight: bold; margin-top: 0;" align="left">
|
|
||||||
Last Response</h1>
|
|
||||||
<p style="box-sizing: border-box; color: #74787E; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; font-size: 16px; line-height: 1.5em; margin-top: 0;" align="left">
|
|
||||||
{{ .Service.LastResponse }} </p> {{end}}
|
|
||||||
<table class="body-sub" style="border-top-color: #EDEFF2; border-top-style: solid; border-top-width: 1px; box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; margin-top: 25px; padding-top: 25px;">
|
|
||||||
<td style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; word-break: break-word;"> <a href="/service/{{.Service.Id}}" class="button button--blue" target="_blank" style="-webkit-text-size-adjust: none; background: #3869D4; border-color: #3869d4; border-radius: 3px; border-style: solid; border-width: 10px 18px; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16); box-sizing: border-box; color: #FFF; display: inline-block; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; text-decoration: none;">View Service</a> </td>
|
|
||||||
<td style="box-sizing: border-box; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; word-break: break-word;"> <a href="/dashboard" class="button button--blue" target="_blank" style="-webkit-text-size-adjust: none; background: #3869D4; border-color: #3869d4; border-radius: 3px; border-style: solid; border-width: 10px 18px; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16); box-sizing: border-box; color: #FFF; display: inline-block; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; text-decoration: none;">Statping Dashboard</a> </td>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>`
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mailer *mail.Dialer
|
mailer *mail.Dialer
|
||||||
)
|
)
|
||||||
|
@ -110,9 +35,6 @@ var email = &emailer{¬ifications.Notification{
|
||||||
Author: "Hunter Long",
|
Author: "Hunter Long",
|
||||||
AuthorUrl: "https://github.com/hunterlong",
|
AuthorUrl: "https://github.com/hunterlong",
|
||||||
Icon: "far fa-envelope",
|
Icon: "far fa-envelope",
|
||||||
SuccessData: "Service {{.Service.Name}} is Back Online",
|
|
||||||
FailureData: "Service {{.Service.Name}} is Offline",
|
|
||||||
DataType: "text",
|
|
||||||
Limits: 30,
|
Limits: 30,
|
||||||
Form: []notifications.NotificationForm{{
|
Form: []notifications.NotificationForm{{
|
||||||
Type: "text",
|
Type: "text",
|
||||||
|
@ -145,7 +67,7 @@ var email = &emailer{¬ifications.Notification{
|
||||||
Placeholder: "sendto@email.com",
|
Placeholder: "sendto@email.com",
|
||||||
DbField: "Var2",
|
DbField: "Var2",
|
||||||
}, {
|
}, {
|
||||||
Type: "text",
|
Type: "switch",
|
||||||
Title: "Disable TLS/SSL",
|
Title: "Disable TLS/SSL",
|
||||||
Placeholder: "",
|
Placeholder: "",
|
||||||
SmallText: "To Disable TLS/SSL insert 'true'",
|
SmallText: "To Disable TLS/SSL insert 'true'",
|
||||||
|
@ -166,64 +88,69 @@ type emailOutgoing struct {
|
||||||
// OnFailure will trigger failing service
|
// OnFailure will trigger failing service
|
||||||
func (e *emailer) OnFailure(s *services.Service, f *failures.Failure) (string, error) {
|
func (e *emailer) OnFailure(s *services.Service, f *failures.Failure) (string, error) {
|
||||||
subject := fmt.Sprintf("Service %s is Offline", s.Name)
|
subject := fmt.Sprintf("Service %s is Offline", s.Name)
|
||||||
|
tmpl := renderEmail(s, f)
|
||||||
email := &emailOutgoing{
|
email := &emailOutgoing{
|
||||||
To: e.Var2,
|
To: e.Var2,
|
||||||
Subject: subject,
|
Subject: subject,
|
||||||
Template: mainEmailTemplate,
|
Template: tmpl,
|
||||||
Data: replacer{
|
From: e.Var1,
|
||||||
Service: s,
|
|
||||||
Failure: f,
|
|
||||||
},
|
|
||||||
From: e.Var1,
|
|
||||||
}
|
}
|
||||||
return "email failed", e.dialSend(email)
|
return tmpl, e.dialSend(email)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnSuccess will trigger successful service
|
// OnSuccess will trigger successful service
|
||||||
func (e *emailer) OnSuccess(s *services.Service) (string, error) {
|
func (e *emailer) OnSuccess(s *services.Service) (string, error) {
|
||||||
subject := fmt.Sprintf("Service %s is Back Online", s.Name)
|
subject := fmt.Sprintf("Service %s is Back Online", s.Name)
|
||||||
|
tmpl := renderEmail(s, nil)
|
||||||
email := &emailOutgoing{
|
email := &emailOutgoing{
|
||||||
To: e.Var2,
|
To: e.Var2,
|
||||||
Subject: subject,
|
Subject: subject,
|
||||||
Template: mainEmailTemplate,
|
Template: tmpl,
|
||||||
Data: replacer{
|
From: e.Var1,
|
||||||
Service: s,
|
|
||||||
Failure: &failures.Failure{},
|
|
||||||
},
|
|
||||||
From: e.Var1,
|
|
||||||
}
|
}
|
||||||
return "email sent", e.dialSend(email)
|
return tmpl, e.dialSend(email)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderEmail(s *services.Service, f *failures.Failure) string {
|
||||||
|
wr := bytes.NewBuffer(nil)
|
||||||
|
tmpl := template.New("email")
|
||||||
|
tmpl, err := tmpl.Parse(emailBase)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
|
return emailBase
|
||||||
|
}
|
||||||
|
|
||||||
|
data := replacer{
|
||||||
|
Core: core.App,
|
||||||
|
Service: s,
|
||||||
|
Failure: f,
|
||||||
|
Custom: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = tmpl.ExecuteTemplate(wr, "email", data); err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
|
return emailBase
|
||||||
|
}
|
||||||
|
|
||||||
|
return wr.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnTest triggers when this notifier has been saved
|
// OnTest triggers when this notifier has been saved
|
||||||
func (e *emailer) OnTest() (string, error) {
|
func (e *emailer) OnTest() (string, error) {
|
||||||
testService := services.Service{
|
service := services.Example(true)
|
||||||
Id: 1,
|
subject := fmt.Sprintf("Service %v is Back Online", service.Name)
|
||||||
Name: "Example Service",
|
|
||||||
Domain: "https://www.youtube.com/watch?v=-u6DvRyyKGU",
|
|
||||||
ExpectedStatus: 200,
|
|
||||||
Interval: 30,
|
|
||||||
Type: "http",
|
|
||||||
Method: "GET",
|
|
||||||
Timeout: 20,
|
|
||||||
LastStatusCode: 200,
|
|
||||||
Expected: null.NewNullString("test example"),
|
|
||||||
LastResponse: "<html>this is an example response</html>",
|
|
||||||
CreatedAt: utils.Now().Add(-24 * time.Hour),
|
|
||||||
}
|
|
||||||
subject := fmt.Sprintf("Service %v is Back Online", testService.Name)
|
|
||||||
email := &emailOutgoing{
|
email := &emailOutgoing{
|
||||||
To: e.Var2,
|
To: e.Var2,
|
||||||
Subject: subject,
|
Subject: subject,
|
||||||
Template: mainEmailTemplate,
|
Template: renderEmail(service, failures.Example()),
|
||||||
Data: replacer{
|
From: e.Var1,
|
||||||
Service: &testService,
|
|
||||||
Failure: &failures.Failure{},
|
|
||||||
},
|
|
||||||
From: e.Var1,
|
|
||||||
}
|
}
|
||||||
err := e.dialSend(email)
|
return subject, e.dialSend(email)
|
||||||
return subject, err
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (e *emailer) OnSave() (string, error) {
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *emailer) dialSend(email *emailOutgoing) error {
|
func (e *emailer) dialSend(email *emailOutgoing) error {
|
||||||
|
@ -236,14 +163,15 @@ func (e *emailer) dialSend(email *emailOutgoing) error {
|
||||||
mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.SetHeader("From", email.From)
|
m.SetAddressHeader("From", email.From, "Statping")
|
||||||
m.SetHeader("To", email.To)
|
m.SetHeader("To", email.To)
|
||||||
m.SetHeader("Subject", email.Subject)
|
m.SetHeader("Subject", email.Subject)
|
||||||
m.SetBody("text/html", ReplaceTemplate(email.Template, email.Data))
|
m.SetBody("text/html", email.Template)
|
||||||
|
|
||||||
if err := mailer.DialAndSend(m); err != nil {
|
if err := mailer.DialAndSend(m); err != nil {
|
||||||
utils.Log.Errorln(fmt.Sprintf("email '%v' sent to: %v (size: %v) %v", email.Subject, email.To, len([]byte(email.Source)), err))
|
utils.Log.Errorln(fmt.Sprintf("email '%v' sent to: %v (size: %v) %v", email.Subject, email.To, len([]byte(email.Source)), err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,628 @@
|
||||||
|
package notifiers
|
||||||
|
|
||||||
|
const emailBase = `
|
||||||
|
{{$banner := "https://assets.statping.com/greenbackground.png"}}
|
||||||
|
{{$color := "#4caf50"}}
|
||||||
|
{{if not .Service.Online}}
|
||||||
|
{{$banner = "https://assets.statping.com/offlinebanner.png"}}
|
||||||
|
{{$color = "#c30c0c"}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title> Statping Service Notification </title>
|
||||||
|
<!--[if !mso]><!-- -->
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<!--<![endif]-->
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<style type="text/css">
|
||||||
|
#outlook a {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table,
|
||||||
|
td {
|
||||||
|
border-collapse: collapse;
|
||||||
|
mso-table-lspace: 0pt;
|
||||||
|
mso-table-rspace: 0pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
height: auto;
|
||||||
|
line-height: 100%;
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
-ms-interpolation-mode: bicubic;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
display: block;
|
||||||
|
margin: 13px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!--[if mso]>
|
||||||
|
<xml>
|
||||||
|
<o:OfficeDocumentSettings>
|
||||||
|
<o:AllowPNG/>
|
||||||
|
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||||
|
</o:OfficeDocumentSettings>
|
||||||
|
</xml>
|
||||||
|
<![endif]-->
|
||||||
|
<!--[if lte mso 11]>
|
||||||
|
<style type="text/css">
|
||||||
|
.mj-outlook-group-fix { width:100% !important; }
|
||||||
|
</style>
|
||||||
|
<![endif]-->
|
||||||
|
<!--[if !mso]><!-->
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700" rel="stylesheet" type="text/css">
|
||||||
|
<style type="text/css">
|
||||||
|
@import url(https://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700);
|
||||||
|
</style>
|
||||||
|
<!--<![endif]-->
|
||||||
|
<style type="text/css">
|
||||||
|
@media only screen and (min-width:480px) {
|
||||||
|
.mj-column-per-100 {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style type="text/css">
|
||||||
|
@media only screen and (max-width:480px) {
|
||||||
|
table.mj-full-width-mobile {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
td.mj-full-width-mobile {
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body style="background-color:#E7E7E7;">
|
||||||
|
<div style="background-color:#E7E7E7;">
|
||||||
|
<!-- Top Bar -->
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table
|
||||||
|
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
|
||||||
|
|
||||||
|
<v:rect style="width:600px;" xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false">
|
||||||
|
<v:fill origin="0.5, 0" position="0.5, 0" src="{{$banner}}" color="#FF3FB4" type="tile" />
|
||||||
|
<v:textbox style="mso-fit-shape-to-text:true" inset="0,0,0,0">
|
||||||
|
<![endif]-->
|
||||||
|
<div style="background:#FF3FB4 url({{$banner}}) top center / auto repeat;margin:0px auto;max-width:600px;">
|
||||||
|
<div style="line-height:0;font-size:0;">
|
||||||
|
<table align="center" background="{{$banner}}" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#FF3FB4 url({{$banner}}) top center / auto repeat;width:100%;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="direction:ltr;font-size:0px;padding:0px;text-align:center;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<td
|
||||||
|
class="" style="vertical-align:top;width:600px;"
|
||||||
|
>
|
||||||
|
<![endif]-->
|
||||||
|
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="width:45px;"> <a href="https://statping.com" target="_blank">
|
||||||
|
|
||||||
|
<img
|
||||||
|
alt="Statping" height="auto" src="https://assets.statping.com/iconlight.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="45"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</a> </td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</v:textbox>
|
||||||
|
</v:rect>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table
|
||||||
|
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
|
||||||
|
<![endif]-->
|
||||||
|
<div style="background:#ffffff;background-color:#ffffff;margin:0px auto;max-width:600px;">
|
||||||
|
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<td
|
||||||
|
class="" style="vertical-align:top;width:600px;"
|
||||||
|
>
|
||||||
|
<![endif]-->
|
||||||
|
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td align="left" style="font-size:0px;padding:15px;word-break:break-word;">
|
||||||
|
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:22px;line-height:30px;text-align:left;color:#000000;">
|
||||||
|
|
||||||
|
{{if .Service.Online}}
|
||||||
|
{{.Service.Name}} is back online.
|
||||||
|
{{else}}
|
||||||
|
{{.Service.Name}} is currently offline, you might want to check it.
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="font-size:0px;padding:20px 0;padding-top:10px;padding-right:0px;padding-bottom:10px;padding-left:0px;word-break:break-word;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table
|
||||||
|
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
|
||||||
|
<![endif]-->
|
||||||
|
<div style="margin:0px auto;max-width:600px;">
|
||||||
|
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="direction:ltr;font-size:0px;padding:20px 0;padding-bottom:10px;padding-left:0px;padding-right:0px;padding-top:10px;text-align:center;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<td
|
||||||
|
class="" style="vertical-align:top;width:600px;"
|
||||||
|
>
|
||||||
|
<![endif]-->
|
||||||
|
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:20px;line-height:1;text-align:center;color:#626262;">
|
||||||
|
{{if .Service.Online}}
|
||||||
|
Online for {{.Service.Uptime.Human}}
|
||||||
|
{{else}}
|
||||||
|
Offline for {{.Service.Downtime.Human}}
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" vertical-align="middle" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:separate;line-height:100%;">
|
||||||
|
<tr>
|
||||||
|
<td align="center" bgcolor="{{$color}}" role="presentation" style="border:none;border-radius:4px;cursor:auto;mso-padding-alt:10px 25px;background:{{$color}};" valign="middle">
|
||||||
|
<a href="{{.Core.Domain}}/service/{{.Service.Id}}" style="display:inline-block;background:{{$color}};color:#ffffff;font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;font-weight:normal;line-height:120%;margin:0;text-decoration:none;text-transform:none;padding:10px 25px;mso-padding-alt:0px;border-radius:4px;"
|
||||||
|
target="_blank">
|
||||||
|
View Dashboard
|
||||||
|
</a> </td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<!-- Bottom Graphic -->
|
||||||
|
<tr>
|
||||||
|
<td style="font-size:0px;padding:0px;word-break:break-word;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table
|
||||||
|
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
|
||||||
|
<![endif]-->
|
||||||
|
<div style="background:#fafafa;background-color:#fafafa;margin:0px auto;max-width:600px;">
|
||||||
|
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#fafafa;background-color:#fafafa;width:100%;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="direction:ltr;font-size:0px;padding:0px;text-align:center;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<td
|
||||||
|
class="" style="vertical-align:top;width:600px;"
|
||||||
|
>
|
||||||
|
<![endif]-->
|
||||||
|
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:20px;line-height:1;text-align:left;color:#626262;">Service Domain</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="left" style="font-size:0px;padding:10px 25px;padding-top:0px;word-break:break-word;">
|
||||||
|
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:14px;line-height:1;text-align:left;color:#626262;">{{.Service.Domain}}</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="font-size:0px;padding:0px;word-break:break-word;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table
|
||||||
|
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
|
||||||
|
<![endif]-->
|
||||||
|
<div style="background:#ffffff;background-color:#ffffff;margin:0px auto;max-width:600px;">
|
||||||
|
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#ffffff;background-color:#ffffff;width:100%;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="direction:ltr;font-size:0px;padding:0px;text-align:center;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<td
|
||||||
|
class="" style="vertical-align:top;width:600px;"
|
||||||
|
>
|
||||||
|
<![endif]-->
|
||||||
|
{{if .Failure}}
|
||||||
|
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:20px;line-height:1;text-align:left;color:#626262;">Current Issue</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="left" style="font-size:0px;padding:10px 25px;padding-top:0px;word-break:break-word;">
|
||||||
|
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:14px;line-height:1;text-align:left;color:#626262;">{{.Failure.Issue}}</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="font-size:0px;word-break:break-word;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td height="30" style="vertical-align:top;height:30px;">
|
||||||
|
|
||||||
|
<![endif]-->
|
||||||
|
<div style="height:30px;"> </div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
|
||||||
|
</td></tr></table>
|
||||||
|
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="font-size:0px;padding:0;word-break:break-word;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table
|
||||||
|
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
|
||||||
|
|
||||||
|
<v:rect style="width:600px;" xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false">
|
||||||
|
<v:fill origin="0.5, 0" position="0.5, 0" src="{{$banner}}" color="#F15822" type="tile" />
|
||||||
|
<v:textbox style="mso-fit-shape-to-text:true" inset="0,0,0,0">
|
||||||
|
<![endif]-->
|
||||||
|
<div style="background:#F15822 url({{$banner}}) top center / auto repeat;margin:0px auto;max-width:600px;">
|
||||||
|
<div style="line-height:0;font-size:0;">
|
||||||
|
<table align="center" background="{{$banner}}" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#F15822 url({{$banner}}) top center / auto repeat;width:100%;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="direction:ltr;font-size:0px;padding:0;text-align:center;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<td
|
||||||
|
class="" style="vertical-align:top;width:600px;"
|
||||||
|
>
|
||||||
|
<![endif]-->
|
||||||
|
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="width:250px;"> <a href="https://www.sphero.com" target="_blank">
|
||||||
|
|
||||||
|
<img
|
||||||
|
height="auto" src="https://assets.statping.com/statpingcom.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="250"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</a> </td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</v:textbox>
|
||||||
|
</v:rect>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="font-size:0px;padding:20px 0;padding-top:10px;padding-bottom:0;word-break:break-word;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table
|
||||||
|
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
|
||||||
|
<![endif]-->
|
||||||
|
<div style="margin:0px auto;max-width:600px;">
|
||||||
|
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="direction:ltr;font-size:0px;padding:20px 0;padding-bottom:0;padding-top:10px;text-align:center;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<td
|
||||||
|
class="" style="vertical-align:top;width:600px;"
|
||||||
|
>
|
||||||
|
<![endif]-->
|
||||||
|
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:11px;line-height:16px;text-align:center;color:#445566;">You are receiving this email because one of your services has changed on your Statping instance. You can modify this email on the Email Notifier page in Settings.</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:11px;line-height:16px;text-align:center;color:#445566;">© Statping</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="font-size:0px;padding:20px 0;padding-top:0;padding-bottom:0;word-break:break-word;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table
|
||||||
|
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
|
||||||
|
<![endif]-->
|
||||||
|
<div style="margin:0px auto;max-width:600px;">
|
||||||
|
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="direction:ltr;font-size:0px;padding:20px 0;padding-bottom:0;padding-top:0;text-align:center;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<td
|
||||||
|
class="" style="width:600px;"
|
||||||
|
>
|
||||||
|
<![endif]-->
|
||||||
|
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0;line-height:0;text-align:left;display:inline-block;width:100%;direction:ltr;">
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
<table
|
||||||
|
border="0" cellpadding="0" cellspacing="0" role="presentation"
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<td
|
||||||
|
style="vertical-align:top;width:600px;"
|
||||||
|
>
|
||||||
|
<![endif]-->
|
||||||
|
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td style="vertical-align:top;padding-right:0;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:11px;font-weight:bold;line-height:16px;text-align:center;color:#445566;"><a class="footer-link" href="https://statping.com">Statping.com</a>         <a class="footer-link" href="https://github.com/statping/statping">Github</a>        
|
||||||
|
<a class="footer-link" href="https://statping.com/privacy">Privacy</a>         <a class="footer-link" href="https://www.google.com">Unsubscribe</a></div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--[if mso | IE]>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<![endif]-->
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
`
|
|
@ -71,3 +71,8 @@ func (l *lineNotifier) OnTest() (string, error) {
|
||||||
_, err := l.sendMessage(msg)
|
_, err := l.sendMessage(msg)
|
||||||
return msg, err
|
return msg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (l *lineNotifier) OnSave() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
|
@ -129,6 +129,11 @@ func (m *mobilePush) Send(pushMessage *pushArray) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (m *mobilePush) OnSave() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func pushRequest(msg *pushArray) ([]byte, error) {
|
func pushRequest(msg *pushArray) ([]byte, error) {
|
||||||
body, err := json.Marshal(&PushNotification{[]*pushArray{msg}})
|
body, err := json.Marshal(&PushNotification{[]*pushArray{msg}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -16,6 +16,7 @@ type replacer struct {
|
||||||
Core *core.Core
|
Core *core.Core
|
||||||
Service *services.Service
|
Service *services.Service
|
||||||
Failure *failures.Failure
|
Failure *failures.Failure
|
||||||
|
Custom map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitNotifiers() {
|
func InitNotifiers() {
|
||||||
|
@ -30,6 +31,7 @@ func InitNotifiers() {
|
||||||
Webhook,
|
Webhook,
|
||||||
Mobile,
|
Mobile,
|
||||||
Pushover,
|
Pushover,
|
||||||
|
statpingMailer,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,3 +90,8 @@ func (t *pushover) OnTest() (string, error) {
|
||||||
content, err := t.sendMessage(msg)
|
content, err := t.sendMessage(msg)
|
||||||
return content, err
|
return content, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (t *pushover) OnSave() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
|
@ -86,3 +86,8 @@ func (s *slack) OnSuccess(srv *services.Service) (string, error) {
|
||||||
out, err := s.sendSlack(msg)
|
out, err := s.sendSlack(msg)
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (s *slack) OnSave() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
package notifiers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/statping/statping/types/core"
|
||||||
|
"github.com/statping/statping/types/failures"
|
||||||
|
"github.com/statping/statping/types/notifications"
|
||||||
|
"github.com/statping/statping/types/notifier"
|
||||||
|
"github.com/statping/statping/types/services"
|
||||||
|
"github.com/statping/statping/utils"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ notifier.Notifier = (*statpingEmailer)(nil)
|
||||||
|
|
||||||
|
const (
|
||||||
|
statpingEmailerName = "statping_emailer"
|
||||||
|
statpingEmailerHost = "https://news.statping.com"
|
||||||
|
)
|
||||||
|
|
||||||
|
type statpingEmailer struct {
|
||||||
|
*notifications.Notification
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statpingEmailer) Select() *notifications.Notification {
|
||||||
|
return s.Notification
|
||||||
|
}
|
||||||
|
|
||||||
|
var statpingMailer = &statpingEmailer{¬ifications.Notification{
|
||||||
|
Method: statpingEmailerName,
|
||||||
|
Title: "Statping Emailer",
|
||||||
|
Description: "Send an email when a service becomes offline or back online using Statping's email service. You will need to verify your email address.",
|
||||||
|
Author: "Hunter Long",
|
||||||
|
AuthorUrl: "https://github.com/hunterlong",
|
||||||
|
Delay: time.Duration(10 * time.Second),
|
||||||
|
Icon: "fas envelope-square",
|
||||||
|
Limits: 60,
|
||||||
|
Form: []notifications.NotificationForm{{
|
||||||
|
Type: "email",
|
||||||
|
Title: "Send to Email Address",
|
||||||
|
Placeholder: "Insert your email address",
|
||||||
|
DbField: "Host",
|
||||||
|
Required: true,
|
||||||
|
}}},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send will send a HTTP Post to the slack webhooker API. It accepts type: string
|
||||||
|
func (s *statpingEmailer) sendStatpingEmail(msg statpingMail) (string, error) {
|
||||||
|
data, _ := json.Marshal(msg)
|
||||||
|
resp, _, err := utils.HttpRequest(statpingEmailerHost+"/notifier", "POST", "application/json", nil, bytes.NewBuffer(data), time.Duration(10*time.Second), true, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statpingEmailer) OnTest() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type statpingMail struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Core *core.Core `json:"core,omitempty"`
|
||||||
|
Service *services.Service `json:"service,omitempty"`
|
||||||
|
Failure *failures.Failure `json:"failure,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnFailure will trigger failing service
|
||||||
|
func (s *statpingEmailer) OnFailure(srv *services.Service, f *failures.Failure) (string, error) {
|
||||||
|
ee := statpingMail{
|
||||||
|
Email: s.Host,
|
||||||
|
Core: core.App,
|
||||||
|
Service: srv,
|
||||||
|
Failure: f,
|
||||||
|
}
|
||||||
|
return s.sendStatpingEmail(ee)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnSuccess will trigger successful service
|
||||||
|
func (s *statpingEmailer) OnSuccess(srv *services.Service) (string, error) {
|
||||||
|
ee := statpingMail{
|
||||||
|
Email: s.Host,
|
||||||
|
Core: core.App,
|
||||||
|
Service: srv,
|
||||||
|
Failure: nil,
|
||||||
|
}
|
||||||
|
return s.sendStatpingEmail(ee)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (s *statpingEmailer) OnSave() (string, error) {
|
||||||
|
ee := statpingMail{
|
||||||
|
Email: s.Host,
|
||||||
|
Core: core.App,
|
||||||
|
Service: nil,
|
||||||
|
Failure: nil,
|
||||||
|
}
|
||||||
|
out, err := s.sendStatpingEmail(ee)
|
||||||
|
log.Println("statping emailer response", out)
|
||||||
|
return out, err
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package notifiers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/statping/statping/database"
|
||||||
|
"github.com/statping/statping/types/failures"
|
||||||
|
"github.com/statping/statping/types/notifications"
|
||||||
|
"github.com/statping/statping/types/null"
|
||||||
|
"github.com/statping/statping/types/services"
|
||||||
|
"github.com/statping/statping/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testEmail string
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStatpingEmailerNotifier(t *testing.T) {
|
||||||
|
err := utils.InitLogs()
|
||||||
|
require.Nil(t, err)
|
||||||
|
db, err := database.OpenTester()
|
||||||
|
require.Nil(t, err)
|
||||||
|
db.AutoMigrate(¬ifications.Notification{})
|
||||||
|
notifications.SetDB(db)
|
||||||
|
|
||||||
|
testEmail = utils.Params.GetString("TEST_EMAIL")
|
||||||
|
statpingMailer.Host = testEmail
|
||||||
|
statpingMailer.Enabled = null.NewNullBool(true)
|
||||||
|
|
||||||
|
if testEmail == "" {
|
||||||
|
t.Log("statping email notifier testing skipped, missing TEST_EMAIL environment variable")
|
||||||
|
t.SkipNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Load statping emailer", func(t *testing.T) {
|
||||||
|
statpingMailer.Host = testEmail
|
||||||
|
statpingMailer.Delay = time.Duration(100 * time.Millisecond)
|
||||||
|
statpingMailer.Limits = 3
|
||||||
|
Add(statpingMailer)
|
||||||
|
assert.Equal(t, "Hunter Long", statpingMailer.Author)
|
||||||
|
assert.Equal(t, testEmail, statpingMailer.Host)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("statping emailer Within Limits", func(t *testing.T) {
|
||||||
|
ok := statpingMailer.CanSend()
|
||||||
|
assert.True(t, ok)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("statping emailer OnFailure", func(t *testing.T) {
|
||||||
|
_, err := statpingMailer.OnFailure(services.Example(false), failures.Example())
|
||||||
|
assert.Nil(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("statping emailer OnSuccess", func(t *testing.T) {
|
||||||
|
_, err := statpingMailer.OnSuccess(services.Example(true))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -94,6 +94,11 @@ func (t *telegram) OnTest() (string, error) {
|
||||||
return content, err
|
return content, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (t *telegram) OnSave() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func telegramSuccess(res []byte) (bool, telegramResponse) {
|
func telegramSuccess(res []byte) (bool, telegramResponse) {
|
||||||
var obj telegramResponse
|
var obj telegramResponse
|
||||||
json.Unmarshal(res, &obj)
|
json.Unmarshal(res, &obj)
|
||||||
|
|
|
@ -107,6 +107,11 @@ func (t *twilio) OnTest() (string, error) {
|
||||||
return t.sendMessage(msg)
|
return t.sendMessage(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (t *twilio) OnSave() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func twilioSuccess(res []byte) (bool, twilioResponse) {
|
func twilioSuccess(res []byte) (bool, twilioResponse) {
|
||||||
var obj twilioResponse
|
var obj twilioResponse
|
||||||
json.Unmarshal(res, &obj)
|
json.Unmarshal(res, &obj)
|
||||||
|
|
|
@ -148,3 +148,8 @@ func (w *webhooker) OnSuccess(s *services.Service) (string, error) {
|
||||||
content, err := ioutil.ReadAll(resp.Body)
|
content, err := ioutil.ReadAll(resp.Body)
|
||||||
return string(content), err
|
return string(content), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (w *webhooker) OnSave() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
|
@ -10,4 +10,5 @@ type Notifier interface {
|
||||||
OnSuccess(*services.Service) (string, error) // OnSuccess is triggered when a service is successful
|
OnSuccess(*services.Service) (string, error) // OnSuccess is triggered when a service is successful
|
||||||
OnFailure(*services.Service, *failures.Failure) (string, error) // OnFailure is triggered when a service is failing
|
OnFailure(*services.Service, *failures.Failure) (string, error) // OnFailure is triggered when a service is failing
|
||||||
OnTest() (string, error) // OnTest is triggered for testing
|
OnTest() (string, error) // OnTest is triggered for testing
|
||||||
|
OnSave() (string, error) // OnSave is triggered for when saved
|
||||||
}
|
}
|
||||||
|
|
|
@ -326,18 +326,13 @@ func (s *Service) OnlineSince(ago time.Time) float32 {
|
||||||
return s.Online24Hours
|
return s.Online24Hours
|
||||||
}
|
}
|
||||||
|
|
||||||
// Downtime returns the amount of time of a offline service
|
func (s *Service) Uptime() utils.Duration {
|
||||||
func (s *Service) Downtime() time.Duration {
|
return utils.Duration{Duration: utils.Now().Sub(s.LastOffline)}
|
||||||
hit := s.LastHit()
|
}
|
||||||
fail := s.AllFailures().Last()
|
|
||||||
if hit == nil {
|
|
||||||
return time.Duration(0)
|
|
||||||
}
|
|
||||||
if fail == nil {
|
|
||||||
return utils.Now().Sub(hit.CreatedAt)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fail.CreatedAt.Sub(hit.CreatedAt)
|
// Downtime returns the amount of time of a offline service
|
||||||
|
func (s *Service) Downtime() utils.Duration {
|
||||||
|
return utils.Duration{Duration: utils.Now().Sub(s.LastOnline)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceOrder will reorder the services based on 'order_id' (Order)
|
// ServiceOrder will reorder the services based on 'order_id' (Order)
|
||||||
|
|
|
@ -29,5 +29,6 @@ type ServiceNotifier interface {
|
||||||
OnSuccess(*Service) (string, error) // OnSuccess is triggered when a service is successful
|
OnSuccess(*Service) (string, error) // OnSuccess is triggered when a service is successful
|
||||||
OnFailure(*Service, *failures.Failure) (string, error) // OnFailure is triggered when a service is failing
|
OnFailure(*Service, *failures.Failure) (string, error) // OnFailure is triggered when a service is failing
|
||||||
OnTest() (string, error) // OnTest is triggered for testing
|
OnTest() (string, error) // OnTest is triggered for testing
|
||||||
|
OnSave() (string, error) // OnSave is triggered for testing
|
||||||
Select() *notifications.Notification // OnTest is triggered for testing
|
Select() *notifications.Notification // OnTest is triggered for testing
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,14 @@ func Example(online bool) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
Id: 6283,
|
Id: 6283,
|
||||||
Name: "Statping Example",
|
Name: "Statping Example",
|
||||||
Domain: "https://localhost:8080",
|
Domain: "https://statping.com",
|
||||||
Expected: null.NewNullString(""),
|
Expected: null.NewNullString(""),
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
Interval: int(time.Duration(15 * time.Second).Seconds()),
|
Interval: int(time.Duration(15 * time.Second).Seconds()),
|
||||||
Type: "http",
|
Type: "http",
|
||||||
Method: "get",
|
Method: "get",
|
||||||
PostData: null.NullString{},
|
PostData: null.NullString{},
|
||||||
Port: 0,
|
Port: 443,
|
||||||
Timeout: int(time.Duration(2 * time.Second).Seconds()),
|
Timeout: int(time.Duration(2 * time.Second).Seconds()),
|
||||||
Order: 0,
|
Order: 0,
|
||||||
VerifySSL: null.NewNullBool(true),
|
VerifySSL: null.NewNullBool(true),
|
||||||
|
@ -46,7 +46,7 @@ func Example(online bool) *Service {
|
||||||
AllowNotifications: null.NewNullBool(true),
|
AllowNotifications: null.NewNullBool(true),
|
||||||
UserNotified: false,
|
UserNotified: false,
|
||||||
UpdateNotify: null.NewNullBool(true),
|
UpdateNotify: null.NewNullBool(true),
|
||||||
DownText: "The service ws responding with 500 status code",
|
DownText: "The service was responding with 500 status code",
|
||||||
SuccessNotified: false,
|
SuccessNotified: false,
|
||||||
LastStatusCode: 200,
|
LastStatusCode: 200,
|
||||||
Failures: nil,
|
Failures: nil,
|
||||||
|
@ -55,9 +55,7 @@ func Example(online bool) *Service {
|
||||||
LastLatency: 124399,
|
LastLatency: 124399,
|
||||||
LastCheck: utils.Now().Add(-37 * time.Second),
|
LastCheck: utils.Now().Add(-37 * time.Second),
|
||||||
LastOnline: utils.Now().Add(-37 * time.Second),
|
LastOnline: utils.Now().Add(-37 * time.Second),
|
||||||
LastOffline: utils.Now().Add((-14 * 24) * time.Hour),
|
LastOffline: utils.Now().Add(-75 * time.Second),
|
||||||
SecondsOnline: int64(utils.Now().Add(-24 * time.Hour).Second()),
|
|
||||||
SecondsOffline: int64(utils.Now().Add(-150 * time.Second).Second()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -432,7 +432,7 @@ func TestServices(t *testing.T) {
|
||||||
item, err := Find(1)
|
item, err := Find(1)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
amount := item.Downtime().Seconds()
|
amount := item.Downtime().Seconds()
|
||||||
assert.Equal(t, "25", fmt.Sprintf("%0.f", amount))
|
assert.Equal(t, "75", fmt.Sprintf("%0.f", amount))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Test Failures Since", func(t *testing.T) {
|
t.Run("Test Failures Since", func(t *testing.T) {
|
||||||
|
|
|
@ -59,9 +59,6 @@ type Service struct {
|
||||||
LastOnline time.Time `gorm:"-" json:"last_success" yaml:"-"`
|
LastOnline time.Time `gorm:"-" json:"last_success" yaml:"-"`
|
||||||
LastOffline time.Time `gorm:"-" json:"last_error" yaml:"-"`
|
LastOffline time.Time `gorm:"-" json:"last_error" yaml:"-"`
|
||||||
Stats *Stats `gorm:"-" json:"stats,omitempty" yaml:"-"`
|
Stats *Stats `gorm:"-" json:"stats,omitempty" yaml:"-"`
|
||||||
|
|
||||||
SecondsOnline int64 `gorm:"-" json:"-" yaml:"-"`
|
|
||||||
SecondsOffline int64 `gorm:"-" json:"-" yaml:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Stats struct {
|
type Stats struct {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/hako/durafmt"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,58 +10,17 @@ func Now() time.Time {
|
||||||
return time.Now().UTC()
|
return time.Now().UTC()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Duration struct {
|
||||||
|
time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Duration) Human() string {
|
||||||
|
return durafmt.Parse(d.Duration).LimitFirstN(2).String()
|
||||||
|
}
|
||||||
|
|
||||||
// FormatDuration converts a time.Duration into a string
|
// FormatDuration converts a time.Duration into a string
|
||||||
func FormatDuration(d time.Duration) string {
|
func FormatDuration(d time.Duration) string {
|
||||||
var out string
|
return durafmt.ParseShort(d).LimitFirstN(3).String()
|
||||||
if d.Hours() >= 24 {
|
|
||||||
out = fmt.Sprintf("%0.0f day", d.Hours()/24)
|
|
||||||
if (d.Hours() / 24) >= 2 {
|
|
||||||
out += "s"
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
} else if d.Hours() >= 1 {
|
|
||||||
out = fmt.Sprintf("%0.0f hour", d.Hours())
|
|
||||||
if d.Hours() >= 2 {
|
|
||||||
out += "s"
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
} else if d.Minutes() >= 1 {
|
|
||||||
out = fmt.Sprintf("%0.0f minute", d.Minutes())
|
|
||||||
if d.Minutes() >= 2 {
|
|
||||||
out += "s"
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
} else if d.Seconds() >= 1 {
|
|
||||||
out = fmt.Sprintf("%0.0f second", d.Seconds())
|
|
||||||
if d.Seconds() >= 2 {
|
|
||||||
out += "s"
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
} else if rev(d.Hours()) >= 24 {
|
|
||||||
out = fmt.Sprintf("%0.0f day", rev(d.Hours()/24))
|
|
||||||
if rev(d.Hours()/24) >= 2 {
|
|
||||||
out += "s"
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
} else if rev(d.Hours()) >= 1 {
|
|
||||||
out = fmt.Sprintf("%0.0f hour", rev(d.Hours()))
|
|
||||||
if rev(d.Hours()) >= 2 {
|
|
||||||
out += "s"
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
} else if rev(d.Minutes()) >= 1 {
|
|
||||||
out = fmt.Sprintf("%0.0f minute", rev(d.Minutes()))
|
|
||||||
if rev(d.Minutes()) >= 2 {
|
|
||||||
out += "s"
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
} else {
|
|
||||||
out = fmt.Sprintf("%0.0f second", rev(d.Seconds()))
|
|
||||||
if rev(d.Seconds()) >= 2 {
|
|
||||||
out += "s"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func rev(f float64) float64 {
|
func rev(f float64) float64 {
|
||||||
|
|
|
@ -89,9 +89,9 @@ func TestDeleteFile(t *testing.T) {
|
||||||
|
|
||||||
func TestFormatDuration(t *testing.T) {
|
func TestFormatDuration(t *testing.T) {
|
||||||
dur, _ := time.ParseDuration("158s")
|
dur, _ := time.ParseDuration("158s")
|
||||||
assert.Equal(t, "3 minutes", FormatDuration(dur))
|
assert.Equal(t, "2 minutes 38 seconds", FormatDuration(dur))
|
||||||
dur, _ = time.ParseDuration("-65s")
|
dur, _ = time.ParseDuration("-65s")
|
||||||
assert.Equal(t, "1 minute", FormatDuration(dur))
|
assert.Equal(t, "-1 minute 5 seconds", FormatDuration(dur))
|
||||||
dur, _ = time.ParseDuration("3s")
|
dur, _ = time.ParseDuration("3s")
|
||||||
assert.Equal(t, "3 seconds", FormatDuration(dur))
|
assert.Equal(t, "3 seconds", FormatDuration(dur))
|
||||||
dur, _ = time.ParseDuration("48h")
|
dur, _ = time.ParseDuration("48h")
|
||||||
|
|
Loading…
Reference in New Issue