2018-08-16 06:22:20 +00:00
// Statup
// Copyright (C) 2018. Hunter Long and the project contributors
// Written by Hunter Long <info@socialeck.com> and the project contributors
//
// https://github.com/hunterlong/statup
//
// 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/>.
2018-07-11 03:06:21 +00:00
package notifiers
import (
2018-07-12 06:53:18 +00:00
"bytes"
2018-09-15 22:21:58 +00:00
"crypto/tls"
2018-07-11 03:06:21 +00:00
"fmt"
2018-09-27 03:20:02 +00:00
"github.com/go-mail/mail"
2018-09-12 04:14:22 +00:00
"github.com/hunterlong/statup/core/notifier"
2018-07-12 06:53:18 +00:00
"github.com/hunterlong/statup/types"
2018-07-11 03:06:21 +00:00
"github.com/hunterlong/statup/utils"
2018-07-12 06:53:18 +00:00
"html/template"
2018-09-27 03:20:02 +00:00
"net/smtp"
2018-10-16 08:30:10 +00:00
"time"
2018-07-11 03:06:21 +00:00
)
const (
2018-10-06 05:05:50 +00:00
mainEmailTemplate = ` < ! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
2018-09-28 06:57:03 +00:00
< 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" / >
2018-10-06 05:00:40 +00:00
< title > Statup email < / title >
2018-09-28 06:57:03 +00:00
< / 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 : # 74787 E ;
- webkit - text - size - adjust : none ;
}
@ media only screen and ( max - width : 600 px ) {
. email - body_inner {
width : 100 % ! important ;
}
. email - footer {
width : 100 % ! important ;
}
}
@ media only screen and ( max - width : 500 px ) {
. 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 Statup 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 Statup 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;" > Statup Dashboard < / a > < / td >
< / table >
< / td >
< / tr >
< / table >
< / td >
< / tr >
< / table >
< / td >
< / tr >
< / table >
< / body >
< / html > `
2018-07-11 03:06:21 +00:00
)
var (
2018-09-27 03:20:02 +00:00
mailer * mail . Dialer
2018-07-11 03:06:21 +00:00
)
2018-10-06 05:00:40 +00:00
type email struct {
2018-09-12 04:14:22 +00:00
* notifier . Notification
2018-07-11 03:06:21 +00:00
}
2018-10-06 05:00:40 +00:00
var emailer = & email { & notifier . Notification {
2018-09-15 01:18:21 +00:00
Method : "email" ,
2018-10-06 05:00:40 +00:00
Title : "email" ,
2018-09-28 06:57:03 +00:00
Description : "Send emails via SMTP when services are online or offline." ,
2018-09-15 01:18:21 +00:00
Author : "Hunter Long" ,
AuthorUrl : "https://github.com/hunterlong" ,
2018-10-21 16:22:26 +00:00
Icon : "far fa-envelope" ,
2018-09-15 01:18:21 +00:00
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" ,
2018-10-06 05:00:40 +00:00
Title : "Outgoing email Address" ,
Placeholder : "Insert your Outgoing email Address" ,
2018-09-15 01:18:21 +00:00
DbField : "Var1" ,
} , {
Type : "email" ,
Title : "Send Alerts To" ,
2018-10-06 05:00:40 +00:00
Placeholder : "email Address" ,
2018-09-15 01:18:21 +00:00
DbField : "Var2" ,
} } ,
} }
2018-07-11 03:06:21 +00:00
func init ( ) {
2018-09-12 04:14:22 +00:00
err := notifier . AddNotifier ( emailer )
2018-09-10 09:01:04 +00:00
if err != nil {
2018-09-12 04:14:22 +00:00
panic ( err )
2018-07-12 06:53:18 +00:00
}
2018-07-11 03:06:21 +00:00
}
2018-10-06 05:03:10 +00:00
// Send will send the SMTP email with your authentication It accepts type: *emailOutgoing
2018-10-06 05:00:40 +00:00
func ( u * email ) Send ( msg interface { } ) error {
2018-10-06 05:03:10 +00:00
email := msg . ( * emailOutgoing )
2018-09-15 22:21:58 +00:00
err := u . dialSend ( email )
if err != nil {
2018-10-06 05:00:40 +00:00
utils . Log ( 3 , fmt . Sprintf ( "email Notifier could not send email: %v" , err ) )
2018-09-15 22:21:58 +00:00
return err
}
2018-07-12 06:53:18 +00:00
return nil
}
2018-10-06 05:03:10 +00:00
type emailOutgoing struct {
2018-07-17 09:18:20 +00:00
To string
Subject string
Template string
From string
Data interface { }
Source string
Sent bool
}
2018-09-15 22:39:17 +00:00
// OnFailure will trigger failing service
2018-10-06 05:00:40 +00:00
func ( u * email ) OnFailure ( s * types . Service , f * types . Failure ) {
2018-10-06 05:03:10 +00:00
email := & emailOutgoing {
2018-10-16 08:30:10 +00:00
To : u . Var2 ,
2018-09-15 01:18:21 +00:00
Subject : fmt . Sprintf ( "Service %v is Failing" , s . Name ) ,
2018-10-06 05:05:50 +00:00
Template : mainEmailTemplate ,
2018-09-15 01:18:21 +00:00
Data : interface { } ( s ) ,
2018-10-16 08:30:10 +00:00
From : u . Var1 ,
2018-07-12 04:49:18 +00:00
}
2018-09-15 01:18:21 +00:00
u . AddQueue ( email )
2018-09-20 09:46:51 +00:00
u . Online = false
2018-07-11 03:06:21 +00:00
}
2018-09-15 22:39:17 +00:00
// OnSuccess will trigger successful service
2018-10-06 05:00:40 +00:00
func ( u * email ) OnSuccess ( s * types . Service ) {
2018-09-20 09:46:51 +00:00
if ! u . Online {
2018-10-27 09:27:09 +00:00
u . ResetQueue ( )
2018-10-06 05:03:10 +00:00
email := & emailOutgoing {
2018-10-16 08:30:10 +00:00
To : u . Var2 ,
2018-09-20 09:46:51 +00:00
Subject : fmt . Sprintf ( "Service %v is Back Online" , s . Name ) ,
2018-10-06 05:05:50 +00:00
Template : mainEmailTemplate ,
2018-09-20 09:46:51 +00:00
Data : interface { } ( s ) ,
2018-10-16 08:30:10 +00:00
From : u . Var1 ,
2018-09-20 09:46:51 +00:00
}
u . AddQueue ( email )
}
u . Online = true
2018-07-11 03:06:21 +00:00
}
2018-10-06 05:00:40 +00:00
func ( u * email ) Select ( ) * notifier . Notification {
2018-09-15 01:18:21 +00:00
return u . Notification
}
2018-09-15 22:39:17 +00:00
// OnSave triggers when this notifier has been saved
2018-10-06 05:00:40 +00:00
func ( u * email ) OnSave ( ) error {
2018-07-11 03:06:21 +00:00
utils . Log ( 1 , fmt . Sprintf ( "Notification %v is receiving updated information." , u . Method ) )
// Do updating stuff here
return nil
}
2018-09-27 03:20:02 +00:00
// OnTest triggers when this notifier has been saved
2018-10-06 05:00:40 +00:00
func ( u * email ) OnTest ( ) error {
2018-09-27 03:20:02 +00:00
host := fmt . Sprintf ( "%v:%v" , u . Host , u . Port )
dial , err := smtp . Dial ( host )
if err != nil {
2018-10-16 08:30:10 +00:00
return err
}
err = dial . StartTLS ( & tls . Config { InsecureSkipVerify : true } )
if err != nil {
2018-09-27 03:20:02 +00:00
return err
}
auth := smtp . PlainAuth ( "" , u . Username , u . Password , host )
2018-10-16 08:30:10 +00:00
err = dial . Auth ( auth )
if err != nil {
return err
}
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 : "test example" ,
LastResponse : "<html>this is an example response</html>" ,
CreatedAt : time . Now ( ) . Add ( - 24 * time . Hour ) ,
}
email := & emailOutgoing {
To : u . Var2 ,
Subject : fmt . Sprintf ( "Service %v is Back Online" , testService . Name ) ,
Template : mainEmailTemplate ,
Data : interface { } ( testService ) ,
From : u . Var1 ,
}
err = u . Send ( email )
return err
2018-09-27 03:20:02 +00:00
}
2018-10-06 05:03:10 +00:00
func ( u * email ) dialSend ( email * emailOutgoing ) error {
2018-09-27 03:20:02 +00:00
mailer = mail . NewDialer ( emailer . Host , emailer . Port , emailer . Username , emailer . Password )
2018-09-15 22:21:58 +00:00
mailer . TLSConfig = & tls . Config { InsecureSkipVerify : true }
emailSource ( email )
2018-09-27 03:20:02 +00:00
m := mail . NewMessage ( )
2018-07-12 06:53:18 +00:00
m . SetHeader ( "From" , email . From )
m . SetHeader ( "To" , email . To )
m . SetHeader ( "Subject" , email . Subject )
m . SetBody ( "text/html" , email . Source )
2018-07-16 07:02:33 +00:00
if err := mailer . DialAndSend ( m ) ; err != nil {
2018-10-06 05:00:40 +00:00
utils . Log ( 3 , fmt . Sprintf ( "email '%v' sent to: %v using the %v template (size: %v) %v" , email . Subject , email . To , email . Template , len ( [ ] byte ( email . Source ) ) , err ) )
2018-07-12 06:53:18 +00:00
return err
}
return nil
}
2018-10-06 05:03:10 +00:00
func emailSource ( email * emailOutgoing ) {
source := emailTemplate ( email . Template , email . Data )
2018-07-12 06:53:18 +00:00
email . Source = source
}
2018-10-06 05:03:10 +00:00
func emailTemplate ( contents string , data interface { } ) string {
2018-07-12 06:53:18 +00:00
t := template . New ( "email" )
2018-09-15 01:18:21 +00:00
t , err := t . Parse ( contents )
2018-07-12 06:53:18 +00:00
if err != nil {
utils . Log ( 3 , err )
}
var tpl bytes . Buffer
if err := t . Execute ( & tpl , data ) ; err != nil {
utils . Log ( 2 , err )
}
result := tpl . String ( )
return result
}