From d16c2aad723456eefb0ad11386de0fcfe84a8877 Mon Sep 17 00:00:00 2001 From: hunterlong Date: Wed, 22 Jul 2020 12:07:42 -0700 Subject: [PATCH] convert notifier struct values to nullstring's --- CHANGELOG.md | 1 + notifiers/command.go | 11 ++++--- notifiers/command_test.go | 6 ++-- notifiers/discord.go | 13 ++++---- notifiers/discord_test.go | 4 +-- notifiers/email.go | 16 ++++----- notifiers/email_test.go | 14 ++++---- notifiers/gotify.go | 17 +++++----- notifiers/gotify_test.go | 4 +-- notifiers/mobile.go | 4 +-- notifiers/mobile_test.go | 15 ++++----- notifiers/pushover.go | 19 +++++------ notifiers/pushover_test.go | 8 ++--- notifiers/slack.go | 17 +++++----- notifiers/slack_test.go | 10 +++--- notifiers/statping_emailer.go | 6 ++-- notifiers/statping_emailer_test.go | 6 ++-- notifiers/telegram.go | 17 +++++----- notifiers/telegram_test.go | 22 ++++++------- notifiers/twilio.go | 17 +++++----- notifiers/twilio_test.go | 10 +++--- notifiers/webhook.go | 21 ++++++------ notifiers/webhook_test.go | 8 ++--- types/notifications/database.go | 4 +-- types/notifications/methods.go | 16 ++++----- types/notifications/struct.go | 52 +++++++++++++++--------------- 26 files changed, 172 insertions(+), 166 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cd11683..0021d922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Modified SASS api endpoints (base, layout, forms, mixins, mobile, variables) - Added additional testing - Modified node version from 10.x to 12.18.2 +- Modified Notifier's struct values to be NullString and NullInt to allow empty values # 0.90.60 (07-15-2020) - Added LETSENCRYPT_ENABLE (boolean) env to enable/disable letsencrypt SSL diff --git a/notifiers/command.go b/notifiers/command.go index bc44c285..1c0a59f6 100644 --- a/notifiers/command.go +++ b/notifiers/command.go @@ -5,6 +5,7 @@ import ( "github.com/statping/statping/types/failures" "github.com/statping/statping/types/notifications" "github.com/statping/statping/types/notifier" + "github.com/statping/statping/types/null" "github.com/statping/statping/types/services" "github.com/statping/statping/utils" "strings" @@ -29,8 +30,8 @@ var Command = &commandLine{¬ifications.Notification{ AuthorUrl: "https://github.com/hunterlong", Delay: time.Duration(1 * time.Second), Icon: "fas fa-terminal", - SuccessData: "/usr/bin/curl -L http://localhost:8080", - FailureData: "/usr/bin/curl -L http://localhost:8080", + SuccessData: null.NewNullString("/usr/bin/curl -L http://localhost:8080"), + FailureData: null.NewNullString("/usr/bin/curl -L http://localhost:8080"), DataType: "text", Limits: 60, }} @@ -51,21 +52,21 @@ func runCommand(cmd string) (string, string, error) { // OnSuccess for commandLine will trigger successful service func (c *commandLine) OnSuccess(s services.Service) (string, error) { - tmpl := ReplaceVars(c.SuccessData, s, failures.Failure{}) + tmpl := ReplaceVars(c.SuccessData.String, s, failures.Failure{}) out, _, err := runCommand(tmpl) return out, err } // OnFailure for commandLine will trigger failing service func (c *commandLine) OnFailure(s services.Service, f failures.Failure) (string, error) { - tmpl := ReplaceVars(c.FailureData, s, f) + tmpl := ReplaceVars(c.FailureData.String, s, f) out, _, err := runCommand(tmpl) return out, err } // OnTest for commandLine triggers when this notifier has been saved func (c *commandLine) OnTest() (string, error) { - tmpl := ReplaceVars(c.Var1, services.Example(true), failures.Example()) + tmpl := ReplaceVars(c.Var1.String, services.Example(true), failures.Example()) in, out, err := runCommand(tmpl) utils.Log.Infoln(in) utils.Log.Infoln(out) diff --git a/notifiers/command_test.go b/notifiers/command_test.go index b424fb65..a6e7de6a 100644 --- a/notifiers/command_test.go +++ b/notifiers/command_test.go @@ -25,9 +25,9 @@ func TestCommandNotifier(t *testing.T) { core.Example() t.Run("Load Command", func(t *testing.T) { - Command.Host = "/bin/echo" - Command.Var1 = "service {{.Service.Domain}} is online" - Command.Var2 = "service {{.Service.Domain}} is offline" + Command.Host = null.NewNullString("/bin/echo") + Command.Var1 = null.NewNullString("service {{.Service.Domain}} is online") + Command.Var2 = null.NewNullString("service {{.Service.Domain}} is offline") Command.Delay = time.Duration(100 * time.Millisecond) Command.Limits = 99 Command.Enabled = null.NewNullBool(true) diff --git a/notifiers/discord.go b/notifiers/discord.go index 416ab57d..fefc0c2b 100644 --- a/notifiers/discord.go +++ b/notifiers/discord.go @@ -7,6 +7,7 @@ import ( "github.com/statping/statping/types/failures" "github.com/statping/statping/types/notifications" "github.com/statping/statping/types/notifier" + "github.com/statping/statping/types/null" "github.com/statping/statping/types/services" "github.com/statping/statping/utils" "strings" @@ -26,10 +27,10 @@ var Discorder = &discord{¬ifications.Notification{ Author: "Hunter Long", AuthorUrl: "https://github.com/hunterlong", Delay: time.Duration(5 * time.Second), - Host: "https://discordapp.com/api/webhooks/****/*****", + Host: null.NewNullString("https://discordapp.com/api/webhooks/****/*****"), Icon: "fab fa-discord", - SuccessData: `{"content": "Your service '{{.Service.Name}}' is currently online!"}`, - FailureData: `{"content": "Your service '{{.Service.Name}}' is currently failing! Reason: {{.Failure.Issue}}"}`, + SuccessData: null.NewNullString(`{"content": "Your service '{{.Service.Name}}' is currently online!"}`), + FailureData: null.NewNullString(`{"content": "Your service '{{.Service.Name}}' is currently failing! Reason: {{.Failure.Issue}}"}`), DataType: "json", Limits: 60, Form: []notifications.NotificationForm{{ @@ -52,13 +53,13 @@ func (d *discord) Select() *notifications.Notification { // OnFailure will trigger failing service func (d *discord) OnFailure(s services.Service, f failures.Failure) (string, error) { - out, err := d.sendRequest(ReplaceVars(d.FailureData, s, f)) + out, err := d.sendRequest(ReplaceVars(d.FailureData.String, s, f)) return out, err } // OnSuccess will trigger successful service func (d *discord) OnSuccess(s services.Service) (string, error) { - out, err := d.sendRequest(ReplaceVars(d.SuccessData, s, failures.Failure{})) + out, err := d.sendRequest(ReplaceVars(d.SuccessData.String, s, failures.Failure{})) return out, err } @@ -66,7 +67,7 @@ func (d *discord) OnSuccess(s services.Service) (string, error) { func (d *discord) OnTest() (string, error) { outError := errors.New("Incorrect discord URL, please confirm URL is correct") message := `{"content": "Testing the discord notifier"}` - contents, _, err := utils.HttpRequest(Discorder.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(message)), time.Duration(10*time.Second), true, nil) + contents, _, err := utils.HttpRequest(Discorder.Host.String, "POST", "application/json", nil, bytes.NewBuffer([]byte(message)), time.Duration(10*time.Second), true, nil) if string(contents) == "" { return "", nil } diff --git a/notifiers/discord_test.go b/notifiers/discord_test.go index 7d33b3b1..9ddb87dc 100644 --- a/notifiers/discord_test.go +++ b/notifiers/discord_test.go @@ -35,14 +35,14 @@ func TestDiscordNotifier(t *testing.T) { } t.Run("Load discord", func(t *testing.T) { - Discorder.Host = DISCORD_URL + Discorder.Host = null.NewNullString(DISCORD_URL) Discorder.Delay = time.Duration(100 * time.Millisecond) Discorder.Enabled = null.NewNullBool(true) Add(Discorder) assert.Equal(t, "Hunter Long", Discorder.Author) - assert.Equal(t, DISCORD_URL, Discorder.Host) + assert.Equal(t, DISCORD_URL, Discorder.Host.String) }) t.Run("discord Notifier Tester", func(t *testing.T) { diff --git a/notifiers/email.go b/notifiers/email.go index d3ec0461..baad95d4 100644 --- a/notifiers/email.go +++ b/notifiers/email.go @@ -90,10 +90,10 @@ func (e *emailer) OnFailure(s services.Service, f failures.Failure) (string, err subject := fmt.Sprintf("Service %s is Offline", s.Name) tmpl := renderEmail(s, f) email := &emailOutgoing{ - To: e.Var2, + To: e.Var2.String, Subject: subject, Template: tmpl, - From: e.Var1, + From: e.Var1.String, } return tmpl, e.dialSend(email) } @@ -103,10 +103,10 @@ func (e *emailer) OnSuccess(s services.Service) (string, error) { subject := fmt.Sprintf("Service %s is Back Online", s.Name) tmpl := renderEmail(s, failures.Failure{}) email := &emailOutgoing{ - To: e.Var2, + To: e.Var2.String, Subject: subject, Template: tmpl, - From: e.Var1, + From: e.Var1.String, } return tmpl, e.dialSend(email) } @@ -140,10 +140,10 @@ func (e *emailer) OnTest() (string, error) { service := services.Example(true) subject := fmt.Sprintf("Service %v is Back Online", service.Name) email := &emailOutgoing{ - To: e.Var2, + To: e.Var2.String, Subject: subject, Template: renderEmail(service, failures.Example()), - From: e.Var1, + From: e.Var1.String, } return subject, e.dialSend(email) } @@ -154,10 +154,10 @@ func (e *emailer) OnSave() (string, error) { } func (e *emailer) dialSend(email *emailOutgoing) error { - mailer = mail.NewDialer(e.Host, e.Port, e.Username, e.Password) + mailer = mail.NewDialer(e.Host.String, int(e.Port.Int64), e.Username.String, e.Password.String) m := mail.NewMessage() // if email setting TLS is Disabled - if e.ApiKey == "true" { + if e.ApiKey.String == "true" { mailer.SSL = false } else { mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true} diff --git a/notifiers/email_test.go b/notifiers/email_test.go index cbcec63e..0ef72543 100644 --- a/notifiers/email_test.go +++ b/notifiers/email_test.go @@ -46,18 +46,18 @@ func TestEmailNotifier(t *testing.T) { } t.Run("New email", func(t *testing.T) { - email.Host = EMAIL_HOST - email.Username = EMAIL_USER - email.Password = EMAIL_PASS - email.Var1 = EMAIL_OUTGOING - email.Var2 = EMAIL_SEND_TO - email.Port = int(EMAIL_PORT) + email.Host = null.NewNullString(EMAIL_HOST) + email.Username = null.NewNullString(EMAIL_USER) + email.Password = null.NewNullString(EMAIL_PASS) + email.Var1 = null.NewNullString(EMAIL_OUTGOING) + email.Var2 = null.NewNullString(EMAIL_SEND_TO) + email.Port = null.NewNullInt64(EMAIL_PORT) email.Delay = time.Duration(100 * time.Millisecond) email.Enabled = null.NewNullBool(true) Add(email) assert.Equal(t, "Hunter Long", email.Author) - assert.Equal(t, EMAIL_HOST, email.Host) + assert.Equal(t, EMAIL_HOST, email.Host.String) }) t.Run("email Within Limits", func(t *testing.T) { diff --git a/notifiers/gotify.go b/notifiers/gotify.go index cfdc4aad..9666e270 100644 --- a/notifiers/gotify.go +++ b/notifiers/gotify.go @@ -1,6 +1,7 @@ package notifiers import ( + "github.com/statping/statping/types/null" "strings" "time" @@ -30,8 +31,8 @@ var Gotify = &gotify{¬ifications.Notification{ Icon: "broadcast-tower", Delay: time.Duration(5 * time.Second), Limits: 60, - SuccessData: `{"title": "{{.Service.Name}}", "message": "Your service '{{.Service.Name}}' is currently online!", "priority": 2}`, - FailureData: `{"title": "{{.Service.Name}}", "message": "Your service '{{.Service.Name}}' is currently failing! Reason: {{.Failure.Issue}}", "priority": 5}`, + SuccessData: null.NewNullString(`{"title": "{{.Service.Name}}", "message": "Your service '{{.Service.Name}}' is currently online!", "priority": 2}`), + FailureData: null.NewNullString(`{"title": "{{.Service.Name}}", "message": "Your service '{{.Service.Name}}' is currently failing! Reason: {{.Failure.Issue}}", "priority": 5}`), DataType: "json", Form: []notifications.NotificationForm{{ Type: "text", @@ -53,13 +54,13 @@ var Gotify = &gotify{¬ifications.Notification{ // Send will send a HTTP Post to the Gotify API. It accepts type: string func (g *gotify) sendMessage(msg string) (string, error) { var url string - if strings.HasSuffix(g.Host, "/") { - url = g.Host + "message" + if strings.HasSuffix(g.Host.String, "/") { + url = g.Host.String + "message" } else { - url = g.Host + "/message" + url = g.Host.String + "/message" } - headers := []string{"X-Gotify-Key=" + g.ApiKey} + headers := []string{"X-Gotify-Key=" + g.ApiKey.String} content, _, err := utils.HttpRequest(url, "POST", "application/json", headers, strings.NewReader(msg), time.Duration(10*time.Second), true, nil) @@ -68,13 +69,13 @@ func (g *gotify) sendMessage(msg string) (string, error) { // OnFailure will trigger failing service func (g *gotify) OnFailure(s services.Service, f failures.Failure) (string, error) { - out, err := g.sendMessage(ReplaceVars(g.FailureData, s, f)) + out, err := g.sendMessage(ReplaceVars(g.FailureData.String, s, f)) return out, err } // OnSuccess will trigger successful service func (g *gotify) OnSuccess(s services.Service) (string, error) { - out, err := g.sendMessage(ReplaceVars(g.SuccessData, s, failures.Failure{})) + out, err := g.sendMessage(ReplaceVars(g.SuccessData.String, s, failures.Failure{})) return out, err } diff --git a/notifiers/gotify_test.go b/notifiers/gotify_test.go index d1718629..eefd1c3a 100644 --- a/notifiers/gotify_test.go +++ b/notifiers/gotify_test.go @@ -42,14 +42,14 @@ func TestGotifyNotifier(t *testing.T) { } t.Run("Load gotify", func(t *testing.T) { - Gotify.Host = GOTIFY_URL + Gotify.Host = null.NewNullString(GOTIFY_URL) Gotify.Delay = time.Duration(100 * time.Millisecond) Gotify.Enabled = null.NewNullBool(true) Add(Gotify) assert.Equal(t, "Hugo van Rijswijk", Gotify.Author) - assert.Equal(t, GOTIFY_URL, Gotify.Host) + assert.Equal(t, GOTIFY_URL, Gotify.Host.String) }) t.Run("gotify Notifier Tester", func(t *testing.T) { diff --git a/notifiers/mobile.go b/notifiers/mobile.go index d3664642..164a22aa 100644 --- a/notifiers/mobile.go +++ b/notifiers/mobile.go @@ -93,7 +93,7 @@ func (m *mobilePush) OnTest() (string, error) { msg := &pushArray{ Message: "Testing the Mobile Notifier", Title: "Testing Notifications", - Tokens: []string{m.Var1}, + Tokens: []string{m.Var1.String}, Platform: 2, } body, err := pushRequest(msg) @@ -115,7 +115,7 @@ func (m *mobilePush) OnTest() (string, error) { // Send will send message to Statping push notifications endpoint func (m *mobilePush) Send(pushMessage *pushArray) error { - pushMessage.Tokens = []string{m.Var1} + pushMessage.Tokens = []string{m.Var1.String} pushMessage.Platform = utils.ToInt(m.Var2) _, err := pushRequest(pushMessage) if err != nil { diff --git a/notifiers/mobile_test.go b/notifiers/mobile_test.go index 5268e1e9..621c8c8c 100644 --- a/notifiers/mobile_test.go +++ b/notifiers/mobile_test.go @@ -24,7 +24,12 @@ func TestMobileNotifier(t *testing.T) { require.Nil(t, err) mobileToken = utils.Params.GetString("MOBILE_TOKEN") - Mobile.Var1 = mobileToken + if mobileToken == "" { + t.Log("Mobile notifier testing skipped, missing MOBILE_ID environment variable") + t.SkipNow() + } + + Mobile.Var1 = null.NewNullString(mobileToken) db, err := database.OpenTester() require.Nil(t, err) @@ -32,14 +37,8 @@ func TestMobileNotifier(t *testing.T) { notifications.SetDB(db) core.Example() - Mobile.Var1 = mobileToken - if mobileToken == "" { - t.Log("Mobile notifier testing skipped, missing MOBILE_ID environment variable") - t.SkipNow() - } - t.Run("Load Mobile", func(t *testing.T) { - Mobile.Var1 = mobileToken + Mobile.Var1 = null.NewNullString(mobileToken) Mobile.Delay = time.Duration(100 * time.Millisecond) Mobile.Limits = 10 Mobile.Enabled = null.NewNullBool(true) diff --git a/notifiers/pushover.go b/notifiers/pushover.go index 623eb0fd..b682a8bb 100644 --- a/notifiers/pushover.go +++ b/notifiers/pushover.go @@ -5,6 +5,7 @@ import ( "github.com/statping/statping/types/failures" "github.com/statping/statping/types/notifications" "github.com/statping/statping/types/notifier" + "github.com/statping/statping/types/null" "github.com/statping/statping/types/services" "github.com/statping/statping/utils" "net/url" @@ -35,8 +36,8 @@ var Pushover = &pushover{¬ifications.Notification{ Icon: "fa dot-circle", Delay: time.Duration(10 * time.Second), Limits: 60, - SuccessData: `Your service '{{.Service.Name}}' is currently online!`, - FailureData: `Your service '{{.Service.Name}}' is currently offline!`, + SuccessData: null.NewNullString(`Your service '{{.Service.Name}}' is currently online!`), + FailureData: null.NewNullString(`Your service '{{.Service.Name}}' is currently offline!`), DataType: "text", Form: []notifications.NotificationForm{{ Type: "text", @@ -88,12 +89,12 @@ func priority(val string) string { // Send will send a HTTP Post to the Pushover API. It accepts type: string func (t *pushover) sendMessage(message string) (string, error) { v := url.Values{} - v.Set("token", t.ApiSecret) - v.Set("user", t.ApiKey) + v.Set("token", t.ApiSecret.String) + v.Set("user", t.ApiKey.String) v.Set("message", message) - v.Set("priority", priority(t.Var1)) - if t.Var2 != "" { - v.Set("sound", t.Var2) + v.Set("priority", priority(t.Var1.String)) + if t.Var2.String != "" { + v.Set("sound", t.Var2.String) } rb := strings.NewReader(v.Encode()) @@ -106,14 +107,14 @@ func (t *pushover) sendMessage(message string) (string, error) { // OnFailure will trigger failing service func (t *pushover) OnFailure(s services.Service, f failures.Failure) (string, error) { - message := ReplaceVars(t.FailureData, s, f) + message := ReplaceVars(t.FailureData.String, s, f) out, err := t.sendMessage(message) return out, err } // OnSuccess will trigger successful service func (t *pushover) OnSuccess(s services.Service) (string, error) { - message := ReplaceVars(t.SuccessData, s, failures.Failure{}) + message := ReplaceVars(t.SuccessData.String, s, failures.Failure{}) out, err := t.sendMessage(message) return out, err } diff --git a/notifiers/pushover_test.go b/notifiers/pushover_test.go index aea799c0..709d4d16 100644 --- a/notifiers/pushover_test.go +++ b/notifiers/pushover_test.go @@ -37,10 +37,10 @@ func TestPushoverNotifier(t *testing.T) { } t.Run("Load Pushover", func(t *testing.T) { - Pushover.ApiKey = PUSHOVER_TOKEN - Pushover.ApiSecret = PUSHOVER_API - Pushover.Var1 = "Normal" - Pushover.Var2 = "vibrate" + Pushover.ApiKey = null.NewNullString(PUSHOVER_TOKEN) + Pushover.ApiSecret = null.NewNullString(PUSHOVER_API) + Pushover.Var1 = null.NewNullString("Normal") + Pushover.Var2 = null.NewNullString("vibrate") Pushover.Enabled = null.NewNullBool(true) Add(Pushover) diff --git a/notifiers/slack.go b/notifiers/slack.go index 8b1bfdd7..466ba117 100644 --- a/notifiers/slack.go +++ b/notifiers/slack.go @@ -6,6 +6,7 @@ import ( "github.com/statping/statping/types/failures" "github.com/statping/statping/types/notifications" "github.com/statping/statping/types/notifier" + "github.com/statping/statping/types/null" "github.com/statping/statping/types/services" "github.com/statping/statping/utils" "strings" @@ -33,10 +34,10 @@ var slacker = &slack{¬ifications.Notification{ Author: "Hunter Long", AuthorUrl: "https://github.com/hunterlong", Delay: time.Duration(10 * time.Second), - Host: "https://webhooksurl.slack.com/***", + Host: null.NewNullString("https://webhooksurl.slack.com/***"), Icon: "fab fa-slack", - SuccessData: `{ "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "The service {{.Service.Name}} is back online." } }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "View Service", "emoji": true }, "style": "primary", "url": "{{.Core.Domain}}/service/{{.Service.Id}}" }, { "type": "button", "text": { "type": "plain_text", "text": "Go to Statping", "emoji": true }, "url": "{{.Core.Domain}}" } ] } ] }`, - FailureData: `{ "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": ":warning: The service {{.Service.Name}} is currently offline! :warning:" } }, { "type": "divider" }, { "type": "section", "fields": [ { "type": "mrkdwn", "text": "*Service:*\n{{.Service.Name}}" }, { "type": "mrkdwn", "text": "*URL:*\n{{.Service.Domain}}" }, { "type": "mrkdwn", "text": "*Status Code:*\n{{.Service.LastStatusCode}}" }, { "type": "mrkdwn", "text": "*When:*\n{{.Failure.CreatedAt}}" }, { "type": "mrkdwn", "text": "*Downtime:*\n{{.Service.DowntimeAgo}}" }, { "type": "plain_text", "text": "*Error:*\n{{.Failure.Issue}}" } ] }, { "type": "divider" }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "View Offline Service", "emoji": true }, "style": "danger", "url": "{{.Core.Domain}}/service/{{.Service.Id}}" }, { "type": "button", "text": { "type": "plain_text", "text": "Go to Statping", "emoji": true }, "url": "{{.Core.Domain}}" } ] } ] }`, + SuccessData: null.NewNullString(`{ "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": "The service {{.Service.Name}} is back online." } }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "View Service", "emoji": true }, "style": "primary", "url": "{{.Core.Domain}}/service/{{.Service.Id}}" }, { "type": "button", "text": { "type": "plain_text", "text": "Go to Statping", "emoji": true }, "url": "{{.Core.Domain}}" } ] } ] }`), + FailureData: null.NewNullString(`{ "blocks": [ { "type": "section", "text": { "type": "mrkdwn", "text": ":warning: The service {{.Service.Name}} is currently offline! :warning:" } }, { "type": "divider" }, { "type": "section", "fields": [ { "type": "mrkdwn", "text": "*Service:*\n{{.Service.Name}}" }, { "type": "mrkdwn", "text": "*URL:*\n{{.Service.Domain}}" }, { "type": "mrkdwn", "text": "*Status Code:*\n{{.Service.LastStatusCode}}" }, { "type": "mrkdwn", "text": "*When:*\n{{.Failure.CreatedAt}}" }, { "type": "mrkdwn", "text": "*Downtime:*\n{{.Service.DowntimeAgo}}" }, { "type": "plain_text", "text": "*Error:*\n{{.Failure.Issue}}" } ] }, { "type": "divider" }, { "type": "actions", "elements": [ { "type": "button", "text": { "type": "plain_text", "text": "View Offline Service", "emoji": true }, "style": "danger", "url": "{{.Core.Domain}}/service/{{.Service.Id}}" }, { "type": "button", "text": { "type": "plain_text", "text": "Go to Statping", "emoji": true }, "url": "{{.Core.Domain}}" } ] } ] }`), DataType: "json", RequestInfo: "Slack allows you to customize your own messages with many complex components. Checkout the Slack Message API to learn how you can create your own.", Limits: 60, @@ -52,7 +53,7 @@ var slacker = &slack{¬ifications.Notification{ // Send will send a HTTP Post to the slack webhooker API. It accepts type: string func (s *slack) sendSlack(msg string) (string, error) { - resp, _, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true, nil) + resp, _, err := utils.HttpRequest(s.Host.String, "POST", "application/json", nil, strings.NewReader(msg), time.Duration(10*time.Second), true, nil) if err != nil { return "", err } @@ -61,8 +62,8 @@ func (s *slack) sendSlack(msg string) (string, error) { func (s *slack) OnTest() (string, error) { example := services.Example(true) - testMsg := ReplaceVars(s.SuccessData, example, failures.Failure{}) - contents, resp, err := utils.HttpRequest(s.Host, "POST", "application/json", nil, bytes.NewBuffer([]byte(testMsg)), time.Duration(10*time.Second), true, nil) + testMsg := ReplaceVars(s.SuccessData.String, example, failures.Failure{}) + contents, resp, err := utils.HttpRequest(s.Host.String, "POST", "application/json", nil, bytes.NewBuffer([]byte(testMsg)), time.Duration(10*time.Second), true, nil) if err != nil { return "", err } @@ -75,14 +76,14 @@ func (s *slack) OnTest() (string, error) { // OnFailure will trigger failing service func (s *slack) OnFailure(srv services.Service, f failures.Failure) (string, error) { - msg := ReplaceVars(s.FailureData, srv, f) + msg := ReplaceVars(s.FailureData.String, srv, f) out, err := s.sendSlack(msg) return out, err } // OnSuccess will trigger successful service func (s *slack) OnSuccess(srv services.Service) (string, error) { - msg := ReplaceVars(s.SuccessData, srv, failures.Failure{}) + msg := ReplaceVars(s.SuccessData.String, srv, failures.Failure{}) out, err := s.sendSlack(msg) return out, err } diff --git a/notifiers/slack_test.go b/notifiers/slack_test.go index cc05def5..dd02a851 100644 --- a/notifiers/slack_test.go +++ b/notifiers/slack_test.go @@ -28,21 +28,21 @@ func TestSlackNotifier(t *testing.T) { core.Example() SLACK_URL = utils.Params.GetString("SLACK_URL") - slacker.Host = SLACK_URL - slacker.Enabled = null.NewNullBool(true) - if SLACK_URL == "" { t.Log("slack notifier testing skipped, missing SLACK_URL environment variable") t.SkipNow() } + slacker.Host = null.NewNullString(SLACK_URL) + slacker.Enabled = null.NewNullBool(true) + t.Run("Load slack", func(t *testing.T) { - slacker.Host = SLACK_URL + slacker.Host = null.NewNullString(SLACK_URL) slacker.Delay = time.Duration(100 * time.Millisecond) slacker.Limits = 3 Add(slacker) assert.Equal(t, "Hunter Long", slacker.Author) - assert.Equal(t, SLACK_URL, slacker.Host) + assert.Equal(t, SLACK_URL, slacker.Host.String) }) t.Run("slack Within Limits", func(t *testing.T) { diff --git a/notifiers/statping_emailer.go b/notifiers/statping_emailer.go index a6b5165d..52f6d69b 100644 --- a/notifiers/statping_emailer.go +++ b/notifiers/statping_emailer.go @@ -69,7 +69,7 @@ type statpingMail struct { // OnFailure will trigger failing service func (s *statpingEmailer) OnFailure(srv services.Service, f failures.Failure) (string, error) { ee := statpingMail{ - Email: s.Host, + Email: s.Host.String, Core: *core.App, Service: srv, Failure: f, @@ -80,7 +80,7 @@ func (s *statpingEmailer) OnFailure(srv services.Service, f failures.Failure) (s // OnSuccess will trigger successful service func (s *statpingEmailer) OnSuccess(srv services.Service) (string, error) { ee := statpingMail{ - Email: s.Host, + Email: s.Host.String, Core: *core.App, Service: srv, Failure: failures.Failure{}, @@ -91,7 +91,7 @@ func (s *statpingEmailer) OnSuccess(srv services.Service) (string, error) { // OnSave will trigger when this notifier is saved func (s *statpingEmailer) OnSave() (string, error) { ee := statpingMail{ - Email: s.Host, + Email: s.Host.String, Core: *core.App, Service: services.Service{}, Failure: failures.Failure{}, diff --git a/notifiers/statping_emailer_test.go b/notifiers/statping_emailer_test.go index 76ebf05f..953b6301 100644 --- a/notifiers/statping_emailer_test.go +++ b/notifiers/statping_emailer_test.go @@ -28,7 +28,7 @@ func TestStatpingEmailerNotifier(t *testing.T) { core.Example() testEmail = utils.Params.GetString("TEST_EMAIL") - statpingMailer.Host = testEmail + statpingMailer.Host = null.NewNullString(testEmail) statpingMailer.Enabled = null.NewNullBool(true) if testEmail == "" { @@ -37,12 +37,12 @@ func TestStatpingEmailerNotifier(t *testing.T) { } t.Run("Load statping emailer", func(t *testing.T) { - statpingMailer.Host = testEmail + statpingMailer.Host = null.NewNullString(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) + assert.Equal(t, testEmail, statpingMailer.Host.String) }) t.Run("statping emailer Within Limits", func(t *testing.T) { diff --git a/notifiers/telegram.go b/notifiers/telegram.go index 8af363b5..fa93cf9e 100644 --- a/notifiers/telegram.go +++ b/notifiers/telegram.go @@ -7,6 +7,7 @@ import ( "github.com/statping/statping/types/failures" "github.com/statping/statping/types/notifications" "github.com/statping/statping/types/notifier" + "github.com/statping/statping/types/null" "github.com/statping/statping/types/services" "github.com/statping/statping/utils" "net/url" @@ -32,8 +33,8 @@ var Telegram = &telegram{¬ifications.Notification{ AuthorUrl: "https://github.com/hunterlong", Icon: "fab fa-telegram-plane", Delay: time.Duration(5 * time.Second), - SuccessData: "Your service '{{.Service.Name}}' is currently online!", - FailureData: "Your service '{{.Service.Name}}' is currently offline!", + SuccessData: null.NewNullString("Your service '{{.Service.Name}}' is currently online!"), + FailureData: null.NewNullString("Your service '{{.Service.Name}}' is currently offline!"), DataType: "text", Limits: 60, Form: []notifications.NotificationForm{{ @@ -58,7 +59,7 @@ func (t *telegram) sendMessage(message string) (string, error) { apiEndpoint := fmt.Sprintf("https://api.telegram.org/bot%v/sendMessage", t.ApiSecret) v := url.Values{} - v.Set("chat_id", t.Var1) + v.Set("chat_id", t.Var1.String) v.Set("text", message) contents, _, err := utils.HttpRequest(apiEndpoint, "POST", "application/x-www-form-urlencoded", nil, strings.NewReader(v.Encode()), time.Duration(10*time.Second), true, nil) @@ -74,16 +75,14 @@ func (t *telegram) sendMessage(message string) (string, error) { // OnFailure will trigger failing service func (t *telegram) OnFailure(s services.Service, f failures.Failure) (string, error) { - msg := ReplaceVars(t.FailureData, s, f) - out, err := t.sendMessage(msg) - return out, err + msg := ReplaceVars(t.FailureData.String, s, f) + return t.sendMessage(msg) } // OnSuccess will trigger successful service func (t *telegram) OnSuccess(s services.Service) (string, error) { - msg := ReplaceVars(t.SuccessData, s, failures.Failure{}) - out, err := t.sendMessage(msg) - return out, err + msg := ReplaceVars(t.SuccessData.String, s, failures.Failure{}) + return t.sendMessage(msg) } // OnTest will test the Twilio SMS messaging diff --git a/notifiers/telegram_test.go b/notifiers/telegram_test.go index b7895975..83579407 100644 --- a/notifiers/telegram_test.go +++ b/notifiers/telegram_test.go @@ -20,13 +20,18 @@ var ( ) func TestTelegramNotifier(t *testing.T) { + if telegramToken == "" || telegramChannel == "" { + t.Log("Telegram notifier testing skipped, missing TELEGRAM_TOKEN and TELEGRAM_CHANNEL environment variable") + t.SkipNow() + } + err := utils.InitLogs() require.Nil(t, err) telegramToken = utils.Params.GetString("TELEGRAM_TOKEN") telegramChannel = utils.Params.GetString("TELEGRAM_CHANNEL") - Telegram.ApiSecret = telegramToken - Telegram.Var1 = telegramChannel + Telegram.ApiSecret = null.NewNullString(telegramToken) + Telegram.Var1 = null.NewNullString(telegramChannel) db, err := database.OpenTester() require.Nil(t, err) @@ -34,22 +39,17 @@ func TestTelegramNotifier(t *testing.T) { notifications.SetDB(db) core.Example() - if telegramToken == "" || telegramChannel == "" { - t.Log("Telegram notifier testing skipped, missing TELEGRAM_TOKEN and TELEGRAM_CHANNEL environment variable") - t.SkipNow() - } - t.Run("Load Telegram", func(t *testing.T) { - Telegram.ApiSecret = telegramToken - Telegram.Var1 = telegramChannel + Telegram.ApiSecret = null.NewNullString(telegramToken) + Telegram.Var1 = null.NewNullString(telegramChannel) Telegram.Delay = time.Duration(1 * time.Second) Telegram.Enabled = null.NewNullBool(true) Add(Telegram) assert.Equal(t, "Hunter Long", Telegram.Author) - assert.Equal(t, telegramToken, Telegram.ApiSecret) - assert.Equal(t, telegramChannel, Telegram.Var1) + assert.Equal(t, telegramToken, Telegram.ApiSecret.String) + assert.Equal(t, telegramChannel, Telegram.Var1.String) }) t.Run("Telegram Within Limits", func(t *testing.T) { diff --git a/notifiers/twilio.go b/notifiers/twilio.go index ec46d21a..47ae2024 100644 --- a/notifiers/twilio.go +++ b/notifiers/twilio.go @@ -8,6 +8,7 @@ import ( "github.com/statping/statping/types/failures" "github.com/statping/statping/types/notifications" "github.com/statping/statping/types/notifier" + "github.com/statping/statping/types/null" "github.com/statping/statping/types/services" "github.com/statping/statping/utils" "net/url" @@ -33,8 +34,8 @@ var Twilio = &twilio{¬ifications.Notification{ AuthorUrl: "https://github.com/hunterlong", Icon: "far fa-comment-alt", Delay: time.Duration(10 * time.Second), - SuccessData: "Your service '{{.Service.Name}}' is currently online!", - FailureData: "Your service '{{.Service.Name}}' is currently offline!", + SuccessData: null.NewNullString("Your service '{{.Service.Name}}' is currently online!"), + FailureData: null.NewNullString("Your service '{{.Service.Name}}' is currently offline!"), DataType: "text", Limits: 15, Form: []notifications.NotificationForm{{ @@ -66,15 +67,15 @@ var Twilio = &twilio{¬ifications.Notification{ // Send will send a HTTP Post to the Twilio SMS API. It accepts type: string func (t *twilio) sendMessage(message string) (string, error) { - twilioUrl := fmt.Sprintf("https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json", t.ApiKey) + twilioUrl := fmt.Sprintf("https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json", t.ApiKey.String) v := url.Values{} - v.Set("To", "+"+t.Var1) - v.Set("From", "+"+t.Var2) + v.Set("To", "+"+t.Var1.String) + v.Set("From", "+"+t.Var2.String) v.Set("Body", message) rb := strings.NewReader(v.Encode()) - authHeader := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", t.ApiKey, t.ApiSecret))) + authHeader := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", t.ApiKey.String, t.ApiSecret.String))) contents, _, err := utils.HttpRequest(twilioUrl, "POST", "application/x-www-form-urlencoded", []string{"Authorization=Basic " + authHeader}, rb, 10*time.Second, true, nil) success, _ := twilioSuccess(contents) @@ -91,13 +92,13 @@ func (t *twilio) sendMessage(message string) (string, error) { // OnFailure will trigger failing service func (t *twilio) OnFailure(s services.Service, f failures.Failure) (string, error) { - msg := ReplaceVars(t.FailureData, s, f) + msg := ReplaceVars(t.FailureData.String, s, f) return t.sendMessage(msg) } // OnSuccess will trigger successful service func (t *twilio) OnSuccess(s services.Service) (string, error) { - msg := ReplaceVars(t.SuccessData, s, failures.Failure{}) + msg := ReplaceVars(t.SuccessData.String, s, failures.Failure{}) return t.sendMessage(msg) } diff --git a/notifiers/twilio_test.go b/notifiers/twilio_test.go index f7195811..7cca496f 100644 --- a/notifiers/twilio_test.go +++ b/notifiers/twilio_test.go @@ -38,10 +38,10 @@ func TestTwilioNotifier(t *testing.T) { } t.Run("Load Twilio", func(t *testing.T) { - Twilio.ApiKey = TWILIO_SID - Twilio.ApiSecret = TWILIO_SECRET - Twilio.Var1 = "15005550006" - Twilio.Var2 = "15005550006" + Twilio.ApiKey = null.NewNullString(TWILIO_SID) + Twilio.ApiSecret = null.NewNullString(TWILIO_SECRET) + Twilio.Var1 = null.NewNullString("15005550006") + Twilio.Var2 = null.NewNullString("15005550006") Twilio.Delay = 100 * time.Millisecond Twilio.Enabled = null.NewNullBool(true) @@ -49,7 +49,7 @@ func TestTwilioNotifier(t *testing.T) { assert.Nil(t, err) assert.Equal(t, "Hunter Long", Twilio.Author) - assert.Equal(t, TWILIO_SID, Twilio.ApiKey) + assert.Equal(t, TWILIO_SID, Twilio.ApiKey.String) }) t.Run("Twilio Within Limits", func(t *testing.T) { diff --git a/notifiers/webhook.go b/notifiers/webhook.go index 08bc75fb..ea670e98 100644 --- a/notifiers/webhook.go +++ b/notifiers/webhook.go @@ -6,6 +6,7 @@ import ( "github.com/statping/statping/types/failures" "github.com/statping/statping/types/notifications" "github.com/statping/statping/types/notifier" + "github.com/statping/statping/types/null" "github.com/statping/statping/types/services" "github.com/statping/statping/utils" "io/ioutil" @@ -32,8 +33,8 @@ var Webhook = &webhooker{¬ifications.Notification{ AuthorUrl: "https://github.com/hunterlong", Icon: "fas fa-code-branch", Delay: time.Duration(3 * time.Second), - SuccessData: `{"id": "{{.Service.Id}}", "online": true}`, - FailureData: `{"id": "{{.Service.Id}}", "online": false}`, + SuccessData: null.NewNullString(`{"id": "{{.Service.Id}}", "online": true}`), + FailureData: null.NewNullString(`{"id": "{{.Service.Id}}", "online": false}`), DataType: "json", Limits: 180, Form: []notifications.NotificationForm{{ @@ -83,12 +84,12 @@ func (w *webhooker) sendHttpWebhook(body string) (*http.Response, error) { utils.Log.Infoln(fmt.Sprintf("sending body: '%v' to %v as a %v request", body, w.Host, w.Var1)) client := new(http.Client) client.Timeout = 10 * time.Second - req, err := http.NewRequest(w.Var1, w.Host, bytes.NewBufferString(body)) + req, err := http.NewRequest(w.Var1.String, w.Host.String, bytes.NewBufferString(body)) if err != nil { return nil, err } - if w.ApiSecret != "" { - keyVal := strings.SplitN(w.ApiSecret, "=", 2) + if w.ApiSecret.String != "" { + keyVal := strings.SplitN(w.ApiSecret.String, "=", 2) if len(keyVal) == 2 { if keyVal[0] != "" && keyVal[1] != "" { if strings.ToLower(keyVal[0]) == "host" { @@ -99,8 +100,8 @@ func (w *webhooker) sendHttpWebhook(body string) (*http.Response, error) { } } } - if w.ApiKey != "" { - req.Header.Add("Content-Type", w.ApiKey) + if w.ApiKey.String != "" { + req.Header.Add("Content-Type", w.ApiKey.String) } else { req.Header.Add("Content-Type", "application/json") } @@ -117,7 +118,7 @@ func (w *webhooker) sendHttpWebhook(body string) (*http.Response, error) { func (w *webhooker) OnTest() (string, error) { f := failures.Example() s := services.Example(false) - body := ReplaceVars(w.SuccessData, s, f) + body := ReplaceVars(w.SuccessData.String, s, f) resp, err := w.sendHttpWebhook(body) if err != nil { return "", err @@ -131,7 +132,7 @@ func (w *webhooker) OnTest() (string, error) { // OnFailure will trigger failing service func (w *webhooker) OnFailure(s services.Service, f failures.Failure) (string, error) { - msg := ReplaceVars(w.FailureData, s, f) + msg := ReplaceVars(w.FailureData.String, s, f) resp, err := w.sendHttpWebhook(msg) if err != nil { return "", err @@ -143,7 +144,7 @@ func (w *webhooker) OnFailure(s services.Service, f failures.Failure) (string, e // OnSuccess will trigger successful service func (w *webhooker) OnSuccess(s services.Service) (string, error) { - msg := ReplaceVars(w.SuccessData, s, failures.Failure{}) + msg := ReplaceVars(w.SuccessData.String, s, failures.Failure{}) resp, err := w.sendHttpWebhook(msg) if err != nil { return "", err diff --git a/notifiers/webhook_test.go b/notifiers/webhook_test.go index bb70d8bc..ca1c4483 100644 --- a/notifiers/webhook_test.go +++ b/notifiers/webhook_test.go @@ -31,10 +31,10 @@ func TestWebhookNotifier(t *testing.T) { core.Example() t.Run("Load webhooker", func(t *testing.T) { - Webhook.Host = webhookTestUrl - Webhook.Var1 = "POST" - Webhook.Var2 = webhookMessage - Webhook.ApiKey = "application/json" + Webhook.Host = null.NewNullString(webhookTestUrl) + Webhook.Var1 = null.NewNullString("POST") + Webhook.Var2 = null.NewNullString(webhookMessage) + Webhook.ApiKey = null.NewNullString("application/json") Webhook.Enabled = null.NewNullBool(true) Add(Webhook) diff --git a/types/notifications/database.go b/types/notifications/database.go index 29f923a3..63d04073 100644 --- a/types/notifications/database.go +++ b/types/notifications/database.go @@ -32,10 +32,10 @@ func (n *Notification) Create() error { } return nil } - if p.FailureData == "" { + if p.FailureData.String == "" { p.FailureData = n.FailureData } - if p.SuccessData == "" { + if p.SuccessData.String == "" { p.SuccessData = n.SuccessData } if err := p.Update(); err != nil { diff --git a/types/notifications/methods.go b/types/notifications/methods.go index b17b12ea..f16251b4 100644 --- a/types/notifications/methods.go +++ b/types/notifications/methods.go @@ -45,21 +45,21 @@ func (n *Notification) CanSend() bool { func (n *Notification) GetValue(dbField string) string { switch strings.ToLower(dbField) { case "host": - return n.Host + return n.Host.String case "port": - return fmt.Sprintf("%d", n.Port) + return fmt.Sprintf("%d", n.Port.Int64) case "username": - return n.Username + return n.Username.String case "password": - return n.Password + return n.Password.String case "var1": - return n.Var1 + return n.Var1.String case "var2": - return n.Var2 + return n.Var2.String case "api_key": - return n.ApiKey + return n.ApiKey.String case "api_secret": - return n.ApiSecret + return n.ApiSecret.String case "limits": return utils.ToString(n.Limits) default: diff --git a/types/notifications/struct.go b/types/notifications/struct.go index 30356165..16daec4b 100644 --- a/types/notifications/struct.go +++ b/types/notifications/struct.go @@ -13,32 +13,32 @@ var ( // Notification contains all the fields for a Statping Notifier. type Notification struct { - Id int64 `gorm:"primary_key;column:id" json:"id"` - Method string `gorm:"column:method" json:"method"` - Host string `gorm:"not null;column:host" json:"host,omitempty"` - Port int `gorm:"not null;column:port" json:"port,omitempty"` - Username string `gorm:"not null;column:username" json:"username,omitempty"` - Password string `gorm:"not null;column:password" json:"password,omitempty"` - Var1 string `gorm:"not null;column:var1" json:"var1,omitempty"` - Var2 string `gorm:"not null;column:var2" json:"var2,omitempty"` - ApiKey string `gorm:"not null;column:api_key" json:"api_key,omitempty"` - ApiSecret string `gorm:"not null;column:api_secret" json:"api_secret,omitempty"` - Enabled null.NullBool `gorm:"column:enabled;type:boolean;default:false" json:"enabled,omitempty"` - Limits int `gorm:"not null;column:limits" json:"limits"` - Removable bool `gorm:"column:removable" json:"removable"` - SuccessData string `gorm:"type:text;column:success_data" json:"success_data,omitempty"` - FailureData string `gorm:"type:text;column:failure_data" json:"failure_data,omitempty"` - DataType string `gorm:"-" json:"data_type,omitempty"` - RequestInfo string `gorm:"-" json:"request_info,omitempty"` - CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` - UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` - Title string `gorm:"-" json:"title"` - Description string `gorm:"-" json:"description"` - Author string `gorm:"-" json:"author"` - AuthorUrl string `gorm:"-" json:"author_url"` - Icon string `gorm:"-" json:"icon"` - Delay time.Duration `gorm:"-" json:"delay,string"` - Running chan bool `gorm:"-" json:"-"` + Id int64 `gorm:"primary_key;column:id" json:"id"` + Method string `gorm:"column:method" json:"method"` + Host null.NullString `gorm:"column:host" json:"host,omitempty"` + Port null.NullInt64 `gorm:"column:port" json:"port,omitempty"` + Username null.NullString `gorm:"column:username" json:"username,omitempty"` + Password null.NullString `gorm:"column:password" json:"password,omitempty"` + Var1 null.NullString `gorm:"column:var1" json:"var1,omitempty"` + Var2 null.NullString `gorm:"column:var2" json:"var2,omitempty"` + ApiKey null.NullString `gorm:"column:api_key" json:"api_key,omitempty"` + ApiSecret null.NullString `gorm:"column:api_secret" json:"api_secret,omitempty"` + Enabled null.NullBool `gorm:"column:enabled;type:boolean;default:false" json:"enabled,omitempty"` + Limits int `gorm:"not null;column:limits" json:"limits"` + Removable bool `gorm:"column:removable" json:"removable"` + SuccessData null.NullString `gorm:"type:text;column:success_data" json:"success_data,omitempty"` + FailureData null.NullString `gorm:"type:text;column:failure_data" json:"failure_data,omitempty"` + DataType string `gorm:"-" json:"data_type,omitempty"` + RequestInfo string `gorm:"-" json:"request_info,omitempty"` + CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` + UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` + Title string `gorm:"-" json:"title"` + Description string `gorm:"-" json:"description"` + Author string `gorm:"-" json:"author"` + AuthorUrl string `gorm:"-" json:"author_url"` + Icon string `gorm:"-" json:"icon"` + Delay time.Duration `gorm:"-" json:"delay,string"` + Running chan bool `gorm:"-" json:"-"` Form []NotificationForm `gorm:"-" json:"form"` lastSent time.Time `gorm:"-" json:"-"`