289 lines
12 KiB
Go
289 lines
12 KiB
Go
// Statping
|
|
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
//
|
|
// https://github.com/hunterlong/statping
|
|
//
|
|
// The licenses for most software and other practical works are designed
|
|
// to take away your freedom to share and change the works. By contrast,
|
|
// the GNU General Public License is intended to guarantee your freedom to
|
|
// share and change all versions of a program--to make sure it remains free
|
|
// software for all its users.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package notifiers
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"github.com/go-mail/mail"
|
|
"github.com/hunterlong/statping/core/notifier"
|
|
"github.com/hunterlong/statping/types"
|
|
"github.com/hunterlong/statping/utils"
|
|
"html/template"
|
|
"time"
|
|
)
|
|
|
|
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">
|
|
{{ .Name }} is {{ if .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 .Online }}
|
|
Your Statping service <a target="_blank" href="{{.Domain}}">{{.Name}}</a> is back online. This service has been triggered with a HTTP status code of '{{.LastStatusCode}}' and is currently online based on your requirements. Your service was reported online at {{.CreatedAt}}. </p>
|
|
{{ else }}
|
|
Your Statping service <a target="_blank" href="{{.Domain}}">{{.Name}}</a> has been triggered with a HTTP status code of '{{.LastStatusCode}}' and is currently offline based on your requirements. This failure was created on {{.CreatedAt}}. </p>
|
|
{{ end }}
|
|
|
|
{{if .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">
|
|
{{ .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/{{.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 (
|
|
mailer *mail.Dialer
|
|
)
|
|
|
|
type email struct {
|
|
*notifier.Notification
|
|
}
|
|
|
|
var Emailer = &email{¬ifier.Notification{
|
|
Method: "email",
|
|
Title: "email",
|
|
Description: "Send emails via SMTP when services are online or offline.",
|
|
Author: "Hunter Long",
|
|
AuthorUrl: "https://github.com/hunterlong",
|
|
Icon: "far fa-envelope",
|
|
Form: []notifier.NotificationForm{{
|
|
Type: "text",
|
|
Title: "SMTP Host",
|
|
Placeholder: "Insert your SMTP Host here.",
|
|
DbField: "Host",
|
|
}, {
|
|
Type: "text",
|
|
Title: "SMTP Username",
|
|
Placeholder: "Insert your SMTP Username here.",
|
|
DbField: "Username",
|
|
}, {
|
|
Type: "password",
|
|
Title: "SMTP Password",
|
|
Placeholder: "Insert your SMTP Password here.",
|
|
DbField: "Password",
|
|
}, {
|
|
Type: "number",
|
|
Title: "SMTP Port",
|
|
Placeholder: "Insert your SMTP Port here.",
|
|
DbField: "Port",
|
|
}, {
|
|
Type: "text",
|
|
Title: "Outgoing Email Address",
|
|
Placeholder: "outgoing@email.com",
|
|
DbField: "Var1",
|
|
}, {
|
|
Type: "email",
|
|
Title: "Send Alerts To",
|
|
Placeholder: "sendto@email.com",
|
|
DbField: "Var2",
|
|
}, {
|
|
Type: "text",
|
|
Title: "Disable TLS/SSL",
|
|
Placeholder: "",
|
|
SmallText: "To Disable TLS/SSL insert 'true'",
|
|
DbField: "api_key",
|
|
}},
|
|
}}
|
|
|
|
// Send will send the SMTP email with your authentication It accepts type: *emailOutgoing
|
|
func (u *email) Send(msg interface{}) error {
|
|
email := msg.(*emailOutgoing)
|
|
err := u.dialSend(email)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type emailOutgoing struct {
|
|
To string
|
|
Subject string
|
|
Template string
|
|
From string
|
|
Data interface{}
|
|
Source string
|
|
Sent bool
|
|
}
|
|
|
|
// OnFailure will trigger failing service
|
|
func (u *email) OnFailure(s *types.Service, f *types.Failure) {
|
|
email := &emailOutgoing{
|
|
To: u.Var2,
|
|
Subject: fmt.Sprintf("Service %v is Failing", s.Name),
|
|
Template: mainEmailTemplate,
|
|
Data: interface{}(s),
|
|
From: u.Var1,
|
|
}
|
|
u.AddQueue(fmt.Sprintf("service_%v", s.Id), email)
|
|
}
|
|
|
|
// OnSuccess will trigger successful service
|
|
func (u *email) OnSuccess(s *types.Service) {
|
|
if !s.Online || !s.SuccessNotified {
|
|
var msg string
|
|
if s.UpdateNotify {
|
|
s.UpdateNotify = false
|
|
}
|
|
msg = s.DownText
|
|
|
|
u.ResetUniqueQueue(fmt.Sprintf("service_%v", s.Id))
|
|
email := &emailOutgoing{
|
|
To: u.Var2,
|
|
Subject: msg,
|
|
Template: mainEmailTemplate,
|
|
Data: interface{}(s),
|
|
From: u.Var1,
|
|
}
|
|
u.AddQueue(fmt.Sprintf("service_%v", s.Id), email)
|
|
}
|
|
}
|
|
|
|
func (u *email) Select() *notifier.Notification {
|
|
return u.Notification
|
|
}
|
|
|
|
// OnSave triggers when this notifier has been saved
|
|
func (u *email) OnSave() error {
|
|
utils.Log.Infoln(fmt.Sprintf("Notification %v is receiving updated information.", u.Method))
|
|
// Do updating stuff here
|
|
return nil
|
|
}
|
|
|
|
// OnTest triggers when this notifier has been saved
|
|
func (u *email) OnTest() error {
|
|
testService := &types.Service{
|
|
Id: 1,
|
|
Name: "Example Service",
|
|
Domain: "https://www.youtube.com/watch?v=-u6DvRyyKGU",
|
|
ExpectedStatus: 200,
|
|
Interval: 30,
|
|
Type: "http",
|
|
Method: "GET",
|
|
Timeout: 20,
|
|
LastStatusCode: 200,
|
|
Expected: types.NewNullString("test example"),
|
|
LastResponse: "<html>this is an example response</html>",
|
|
CreatedAt: utils.Now().Add(-24 * time.Hour),
|
|
}
|
|
email := &emailOutgoing{
|
|
To: u.Var2,
|
|
Subject: fmt.Sprintf("Service %v is Back Online", testService.Name),
|
|
Template: mainEmailTemplate,
|
|
Data: testService,
|
|
From: u.Var1,
|
|
}
|
|
return u.dialSend(email)
|
|
}
|
|
|
|
func (u *email) dialSend(email *emailOutgoing) error {
|
|
mailer = mail.NewDialer(Emailer.Host, Emailer.Port, Emailer.Username, Emailer.Password)
|
|
emailSource(email)
|
|
m := mail.NewMessage()
|
|
// if email setting TLS is Disabled
|
|
if u.ApiKey == "true" {
|
|
mailer.SSL = false
|
|
} else {
|
|
mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
|
}
|
|
m.SetHeader("From", email.From)
|
|
m.SetHeader("To", email.To)
|
|
m.SetHeader("Subject", email.Subject)
|
|
m.SetBody("text/html", email.Source)
|
|
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))
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func emailSource(email *emailOutgoing) {
|
|
source := emailTemplate(email.Template, email.Data)
|
|
email.Source = source
|
|
}
|
|
|
|
func emailTemplate(contents string, data interface{}) string {
|
|
t := template.New("email")
|
|
t, err := t.Parse(contents)
|
|
if err != nil {
|
|
utils.Log.Errorln(err)
|
|
}
|
|
var tpl bytes.Buffer
|
|
if err := t.Execute(&tpl, data); err != nil {
|
|
utils.Log.Warnln(err)
|
|
}
|
|
result := tpl.String()
|
|
return result
|
|
}
|