From bf2ece12fe463bf7831bcf5671f706860c1923e8 Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Tue, 10 Jul 2018 05:05:20 -0700 Subject: [PATCH 1/5] new notifier intro update --- cli.go | 6 +- core/communication.go | 101 +++++++++--------- core/core.go | 11 +- core/events.go | 12 +-- core/setup.go | 6 +- handlers/settings.go | 12 +-- nocmmitthis.env | 29 +++++ notifications/slack.go | 61 ----------- .../email.go => notifiers/email_old.go | 6 +- notifiers/notifiers.go | 77 +++++++++++++ notifiers/slack.go | 96 +++++++++++++++++ notifiers/structs.go | 1 + source/tmpl/settings.html | 60 +++++------ types/types.go | 18 ---- 14 files changed, 314 insertions(+), 182 deletions(-) create mode 100644 nocmmitthis.env delete mode 100644 notifications/slack.go rename notifications/email.go => notifiers/email_old.go (96%) create mode 100644 notifiers/notifiers.go create mode 100644 notifiers/slack.go create mode 100644 notifiers/structs.go diff --git a/cli.go b/cli.go index 125438f8..2103accb 100644 --- a/cli.go +++ b/cli.go @@ -4,8 +4,8 @@ import ( "encoding/json" "fmt" "github.com/hunterlong/statup/core" + "github.com/hunterlong/statup/notifiers" "github.com/hunterlong/statup/plugin" - "github.com/hunterlong/statup/types" "github.com/hunterlong/statup/utils" "github.com/joho/godotenv" "io/ioutil" @@ -246,13 +246,13 @@ func FakeSeed(plug plugin.PluginActions) { } fakeUser.Create() - comm := &types.Communication{ + comm := ¬ifiers.Notification{ Id: 1, Method: "email", } core.Create(comm) - comm2 := &types.Communication{ + comm2 := ¬ifiers.Notification{ Id: 2, Method: "slack", } diff --git a/core/communication.go b/core/communication.go index 9bccb2f6..1cf7872f 100644 --- a/core/communication.go +++ b/core/communication.go @@ -1,37 +1,34 @@ package core import ( - "fmt" - "github.com/hunterlong/statup/notifications" - "github.com/hunterlong/statup/types" + "github.com/hunterlong/statup/notifiers" "github.com/hunterlong/statup/utils" - "time" ) func LoadDefaultCommunications() { - notifications.EmailComm = SelectCommunication(1) - emailer := notifications.EmailComm - if emailer.Enabled { - admin, _ := SelectUser(1) - notifications.LoadEmailer(emailer) - email := &types.Email{ - To: admin.Email, - Subject: "Test Email", - Template: "message.html", - Data: nil, - From: emailer.Var1, - } - notifications.SendEmail(EmailBox, email) - go notifications.EmailRoutine() - } - notifications.SlackComm = SelectCommunication(2) - slack := notifications.SlackComm - if slack.Enabled { - notifications.LoadSlack(slack.Host) - msg := fmt.Sprintf("Slack loaded on your Statup Status Page!") - notifications.SendSlack(msg) - go notifications.SlackRoutine() - } + //communications.EmailComm = SelectCommunication(1) + //emailer := communications.EmailComm + //if emailer.Enabled { + // admin, _ := SelectUser(1) + // communications.LoadEmailer(emailer) + // email := &types.Email{ + // To: admin.Email, + // Subject: "Test Email", + // Template: "message.html", + // Data: nil, + // From: emailer.Var1, + // } + // communications.SendEmail(EmailBox, email) + // go communications.EmailRoutine() + //} + //communications.SlackComm = SelectCommunication(2) + //slack := communications.SlackComm + //if slack.Enabled { + // communications.LoadSlack(slack.Host) + // msg := fmt.Sprintf("Slack loaded on your Statup Status Page!") + // communications.SendSlack(msg) + // go communications.SlackRoutine() + //} } func LoadComms() { @@ -42,51 +39,53 @@ func LoadComms() { } } -func SelectAllCommunications() ([]*types.Communication, error) { - var c []*types.Communication +func SelectAllCommunications() ([]*notifiers.Notification, error) { + var c []*notifiers.Notification col := DbSession.Collection("communication").Find() err := col.OrderBy("id").All(&c) - CoreApp.Communications = c + //CoreApp.Communications = c + //communications.LoadComms(c) return c, err } -func Create(c *types.Communication) (int64, error) { - c.CreatedAt = time.Now() - uuid, err := DbSession.Collection("communication").Insert(c) - if err != nil { - utils.Log(3, err) - } - if uuid == nil { - utils.Log(2, err) - return 0, err - } - c.Id = uuid.(int64) - c.Routine = make(chan struct{}) - if CoreApp != nil { - CoreApp.Communications = append(CoreApp.Communications, c) - } - return uuid.(int64), err +func Create(c *notifiers.Notification) (int64, error) { + //c.CreatedAt = time.Now() + //uuid, err := DbSession.Collection("communication").Insert(c) + //if err != nil { + // utils.Log(3, err) + //} + //if uuid == nil { + // utils.Log(2, err) + // return 0, err + //} + //c.Id = uuid.(int64) + //c.Routine = make(chan struct{}) + //if CoreApp != nil { + // CoreApp.Communications = append(CoreApp.Communications, c.Communicator) + //} + //return uuid.(int64), err + return 0, nil } -func Disable(c *types.Communication) { +func Disable(c *notifiers.Notification) { c.Enabled = false Update(c) } -func Enable(c *types.Communication) { +func Enable(c *notifiers.Notification) { c.Enabled = true Update(c) } -func Update(c *types.Communication) *types.Communication { +func Update(c *notifiers.Notification) *notifiers.Notification { col := DbSession.Collection("communication").Find("id", c.Id) col.Update(c) SelectAllCommunications() return c } -func SelectCommunication(id int64) *types.Communication { - var comm *types.Communication +func SelectCommunication(id int64) *notifiers.Notification { + var comm *notifiers.Notification col := DbSession.Collection("communication").Find("id", id) err := col.One(&comm) if err != nil { diff --git a/core/core.go b/core/core.go index d6804229..1d149efc 100644 --- a/core/core.go +++ b/core/core.go @@ -2,6 +2,7 @@ package core import ( "github.com/GeertJohan/go.rice" + "github.com/hunterlong/statup/notifiers" "github.com/hunterlong/statup/plugin" "github.com/hunterlong/statup/types" "github.com/pkg/errors" @@ -28,7 +29,7 @@ type Core struct { Plugins []plugin.Info Repos []PluginJSON AllPlugins []plugin.PluginActions - Communications []*types.Communication + Communications []*notifiers.Notification DbConnection string started time.Time } @@ -59,11 +60,19 @@ func NewCore() *Core { func InitApp() { SelectCore() + + notifiers.Collections = DbSession.Collection("communication") + SelectAllCommunications() InsertDefaultComms() LoadDefaultCommunications() SelectAllServices() CheckServices() + + notifiers.Load() + + CoreApp.Communications = notifiers.AllCommunications + go DatabaseMaintence() } diff --git a/core/events.go b/core/events.go index 29796333..aa4c919a 100644 --- a/core/events.go +++ b/core/events.go @@ -3,7 +3,7 @@ package core import ( "fmt" "github.com/fatih/structs" - "github.com/hunterlong/statup/notifications" + "github.com/hunterlong/statup/notifiers" "github.com/hunterlong/statup/plugin" "github.com/hunterlong/statup/types" "upper.io/db.v3/lib/sqlbuilder" @@ -25,10 +25,10 @@ func OnFailure(s *Service, f FailureData) { for _, p := range CoreApp.AllPlugins { p.OnFailure(structs.Map(s)) } - if notifications.SlackComm != nil { + if notifiers.SendSlack("im failing") != nil { onFailureSlack(s, f) } - if notifications.EmailComm != nil { + if notifiers.EmailComm != nil { onFailureEmail(s, f) } } @@ -36,8 +36,8 @@ func OnFailure(s *Service, f FailureData) { func onFailureSlack(s *Service, f FailureData) { slack := SelectCommunication(2) if slack.Enabled { - msg := fmt.Sprintf("Service %v is currently offline! Issue: %v", s.Name, f.Issue) - notifications.SendSlack(msg) + //msg := fmt.Sprintf("Service %v is currently offline! Issue: %v", s.Name, f.Issue) + //communications.SendSlack(msg) } } @@ -59,7 +59,7 @@ func onFailureEmail(s *Service, f FailureData) { Data: data, From: email.Var1, } - notifications.SendEmail(EmailBox, email) + notifiers.SendEmail(EmailBox, email) } } diff --git a/core/setup.go b/core/setup.go index f81bde73..38f14052 100644 --- a/core/setup.go +++ b/core/setup.go @@ -2,7 +2,7 @@ package core import ( "fmt" - "github.com/hunterlong/statup/types" + "github.com/hunterlong/statup/notifiers" "github.com/hunterlong/statup/utils" "os" ) @@ -10,7 +10,7 @@ import ( func InsertDefaultComms() { emailer := SelectCommunication(1) if emailer == nil { - emailer := &types.Communication{ + emailer := ¬ifiers.Notification{ Method: "email", Removable: false, Enabled: false, @@ -19,7 +19,7 @@ func InsertDefaultComms() { } slack := SelectCommunication(2) if slack == nil { - slack := &types.Communication{ + slack := ¬ifiers.Notification{ Method: "slack", Removable: false, Enabled: false, diff --git a/handlers/settings.go b/handlers/settings.go index f95d95ec..8a19650d 100644 --- a/handlers/settings.go +++ b/handlers/settings.go @@ -2,7 +2,7 @@ package handlers import ( "github.com/hunterlong/statup/core" - "github.com/hunterlong/statup/notifications" + "github.com/hunterlong/statup/notifiers" "github.com/hunterlong/statup/types" "github.com/hunterlong/statup/utils" "net/http" @@ -117,12 +117,12 @@ func SaveEmailSettingsHandler(w http.ResponseWriter, r *http.Request) { Template: "message.html", From: emailer.Var1, } - notifications.LoadEmailer(emailer) - notifications.SendEmail(core.EmailBox, sample) - notifications.EmailComm = emailer + notifiers.LoadEmailer(emailer) + notifiers.SendEmail(core.EmailBox, sample) + notifiers.EmailComm = emailer if emailer.Enabled { utils.Log(1, "Starting Email Routine, 1 unique email per 60 seconds") - go notifications.EmailRoutine() + go notifiers.EmailRoutine() } http.Redirect(w, r, "/settings", http.StatusSeeOther) @@ -140,7 +140,7 @@ func SaveSlackSettingsHandler(w http.ResponseWriter, r *http.Request) { slack.Enabled = false if enable == "on" && slackWebhook != "" { slack.Enabled = true - go notifications.SlackRoutine() + //go communications.SlackRoutine() } slack.Host = slackWebhook core.Update(slack) diff --git a/nocmmitthis.env b/nocmmitthis.env new file mode 100644 index 00000000..ee160523 --- /dev/null +++ b/nocmmitthis.env @@ -0,0 +1,29 @@ +########################### +## Database Information # +########################### +DB_CONNECTION=postgres +DB_HOST=0.0.0.0 +DB_PORT=5432 +DB_USER=root +DB_PASS=password123 +DB_DATABASE=root + +########################### +## STATUP PAGE SETTINGS # +########################### +NAME=Demo +DESCRIPTION=This is an awesome page +DOMAIN=https://domain.com +ADMIN_USER=admin +ADMIN_PASS=admin +ADMIN_EMAIL=info@admin.com +USE_CDN=true + +########################### +## System Values ## +########################### +IS_DOCKER=true +IS_AWS=true +SASS=/usr/local/bin/sass +BASH_ENV=/bin/bash + diff --git a/notifications/slack.go b/notifications/slack.go deleted file mode 100644 index f6e78480..00000000 --- a/notifications/slack.go +++ /dev/null @@ -1,61 +0,0 @@ -package notifications - -import ( - "bytes" - "fmt" - "github.com/hunterlong/statup/types" - "github.com/hunterlong/statup/utils" - "github.com/pkg/errors" - "net/http" - "time" -) - -var ( - slackUrl string - sentLastMin int - slackMessages []string - SlackComm *types.Communication -) - -func LoadSlack(url string) { - if url == "" { - utils.Log(1, "Slack Webhook URL is empty") - return - } - slackUrl = url -} - -func SlackRoutine() { - for _, msg := range slackMessages { - utils.Log(1, fmt.Sprintf("Sending JSON to Slack Webhook: %v", msg)) - client := http.Client{Timeout: 15 * time.Second} - _, err := client.Post(slackUrl, "application/json", bytes.NewBuffer([]byte(msg))) - if err != nil { - utils.Log(3, fmt.Sprintf("Issue sending Slack notification: %v", err)) - } - slackMessages = removeStrArray(slackMessages, msg) - } - time.Sleep(60 * time.Second) - if SlackComm.Enabled { - SlackRoutine() - } -} - -func removeStrArray(arr []string, v string) []string { - var newArray []string - for _, i := range arr { - if i != v { - newArray = append(newArray, v) - } - } - return newArray -} - -func SendSlack(msg string) error { - if slackUrl == "" { - return errors.New("Slack Webhook URL has not been set in settings") - } - fullMessage := fmt.Sprintf("{\"text\":\"%v\"}", msg) - slackMessages = append(slackMessages, fullMessage) - return nil -} diff --git a/notifications/email.go b/notifiers/email_old.go similarity index 96% rename from notifications/email.go rename to notifiers/email_old.go index 49001ee5..5db3b99e 100644 --- a/notifications/email.go +++ b/notifiers/email_old.go @@ -1,4 +1,4 @@ -package notifications +package notifiers import ( "bytes" @@ -15,7 +15,7 @@ import ( var ( mailer *gomail.Dialer emailQueue []*types.Email - EmailComm *types.Communication + EmailComm *Notification ) func EmailRoutine() { @@ -55,7 +55,7 @@ func dialSend(email *types.Email) error { return nil } -func LoadEmailer(mail *types.Communication) { +func LoadEmailer(mail *Notification) { utils.Log(1, fmt.Sprintf("Loading SMTP Emailer using host: %v:%v", mail.Host, mail.Port)) mailer = gomail.NewDialer(mail.Host, mail.Port, mail.Username, mail.Password) mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true} diff --git a/notifiers/notifiers.go b/notifiers/notifiers.go new file mode 100644 index 00000000..343aea42 --- /dev/null +++ b/notifiers/notifiers.go @@ -0,0 +1,77 @@ +package notifiers + +import ( + "github.com/hunterlong/statup/utils" + "time" + "upper.io/db.v3" +) + +var ( + AllCommunications []*Notification + Collections db.Collection +) + +func add(c *Notification) { + AllCommunications = append(AllCommunications, c) +} + +func Load() { + utils.Log(1, "Loading notifiers") + for _, comm := range AllCommunications { + comm.Init() + } +} + +type Notification struct { + Id int64 `db:"id,omitempty" json:"id"` + Method string `db:"method" json:"method"` + Host string `db:"host" json:"-"` + Port int `db:"port" json:"-"` + Username string `db:"username" json:"-"` + Password string `db:"password" json:"-"` + Var1 string `db:"var1" json:"-"` + Var2 string `db:"var2" json:"-"` + ApiKey string `db:"api_key" json:"-"` + ApiSecret string `db:"api_secret" json:"-"` + Enabled bool `db:"enabled" json:"enabled"` + Limits int64 `db:"limits" json:"-"` + Removable bool `db:"removable" json:"-"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + Form []NotificationForm + Routine chan struct{} +} + +type Notifier interface { + Init() error + Run() error + OnFailure() error + OnSuccess() error +} + +type NotificationForm struct { + Type string + Title string + Placeholder string +} + +func OnFailure() { + for _, comm := range AllCommunications { + comm.OnFailure() + } +} + +func OnSuccess() { + for _, comm := range AllCommunications { + comm.OnSuccess() + } +} + +func uniqueMessages(arr []string, v string) []string { + var newArray []string + for _, i := range arr { + if i != v { + newArray = append(newArray, v) + } + } + return newArray +} diff --git a/notifiers/slack.go b/notifiers/slack.go new file mode 100644 index 00000000..783ec229 --- /dev/null +++ b/notifiers/slack.go @@ -0,0 +1,96 @@ +package notifiers + +import ( + "bytes" + "fmt" + "github.com/hunterlong/statup/utils" + "net/http" + "time" +) + +const ( + SLACK_ID int64 = 2 + SLACK_METHOD = "slack" +) + +var ( + slacker *Notification + slackMessages []string +) + +// DEFINE YOUR NOTIFICATION HERE. +func init() { + slacker = &Notification{ + Id: SLACK_ID, + Method: SLACK_METHOD, + Host: "https://webhooksurl.slack.com/***", + Form: []NotificationForm{{ + Type: "text", + Title: "Incoming Webhook Url", + Placeholder: "Insert your Slack webhook URL here.", + }}, + } + add(slacker) +} + +// WHEN NOTIFIER LOADS +func (u *Notification) Init() error { + err := SendSlack("its online") + go u.Run() + return err +} + +// AFTER NOTIFIER LOADS, IF ENABLED, START A QUEUE PROCESS +func (u *Notification) Run() error { + for _, msg := range slackMessages { + utils.Log(1, fmt.Sprintf("Sending JSON to Slack Webhook: %v", msg)) + client := http.Client{Timeout: 15 * time.Second} + _, err := client.Post("https://hooks.slack.com/services/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", "application/json", bytes.NewBuffer([]byte(msg))) + if err != nil { + utils.Log(3, fmt.Sprintf("Issue sending Slack notification: %v", err)) + } + slackMessages = uniqueMessages(slackMessages, msg) + } + time.Sleep(60 * time.Second) + if u.Enabled { + u.Run() + } + return nil +} + +// CUSTOM FUNCTION FO SENDING SLACK MESSAGES +func SendSlack(msg string) error { + //if slackUrl == "" { + // return errors.New("Slack Webhook URL has not been set in settings") + //} + fullMessage := fmt.Sprintf("{\"text\":\"%v\"}", msg) + slackMessages = append(slackMessages, fullMessage) + return nil +} + +// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS +func (u *Notification) OnFailure() error { + utils.Log(1, fmt.Sprintf("Notification %v is receiving a failure notification.", u.Method)) + + // Do failing stuff here! + + return nil +} + +// ON SERVICE SUCCESS, DO YOUR OWN FUNCTIONS +func (u *Notification) OnSuccess() error { + utils.Log(1, fmt.Sprintf("Notification %v is receiving a successful notification.", u.Method)) + + // Do checking or any successful things here + + return nil +} + +// ON SAVE OR UPDATE OF THE NOTIFIER FORM +func (u *Notification) OnSave() error { + utils.Log(1, fmt.Sprintf("Notification %v is receiving updated information.", u.Method)) + + // Do updating stuff here + + return nil +} diff --git a/notifiers/structs.go b/notifiers/structs.go new file mode 100644 index 00000000..48b634c4 --- /dev/null +++ b/notifiers/structs.go @@ -0,0 +1 @@ +package notifiers diff --git a/source/tmpl/settings.html b/source/tmpl/settings.html index 926eea21..b2df7958 100644 --- a/source/tmpl/settings.html +++ b/source/tmpl/settings.html @@ -33,10 +33,11 @@ Settings Theme Editor Email Settings - Slack Updates - {{ range .Communications }} + {{ range .Communications }} + {{.Method}} {{ end }} + Browse Plugins {{ range .Plugins }} {{.Name}} @@ -122,6 +123,33 @@ {{end}} + + {{ range .Communications }} +
+
+ {{range .Form}} +
+ + +
+ {{end}} +
+
+ + + + +
+
+ +
+
+ +
+
+ {{ end }} + + {{ with $c := index .Communications 0 }}
@@ -177,34 +205,6 @@ {{ end }} - {{ with $c := index .Communications 1 }} -
- -
- -
- - -
- -
-
- - - - -
- -
- -
-
- - -
- -
- {{ end }}
{{ range .Repos }} diff --git a/types/types.go b/types/types.go index 7ef3364c..d54bba6e 100644 --- a/types/types.go +++ b/types/types.go @@ -40,24 +40,6 @@ type Checkin struct { Last time.Time `json:"last"` } -type Communication struct { - Id int64 `db:"id,omitempty" json:"id"` - Method string `db:"method" json:"method"` - Host string `db:"host" json:"-"` - Port int `db:"port" json:"-"` - Username string `db:"username" json:"-"` - Password string `db:"password" json:"-"` - Var1 string `db:"var1" json:"-"` - Var2 string `db:"var2" json:"-"` - ApiKey string `db:"api_key" json:"-"` - ApiSecret string `db:"api_secret" json:"-"` - Enabled bool `db:"enabled" json:"enabled"` - Limits int64 `db:"limits" json:"-"` - Removable bool `db:"removable" json:"-"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - Routine chan struct{} -} - type Email struct { To string Subject string From 28c7c8b20198e77d1290768d9af5e17ed4de897d Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Tue, 10 Jul 2018 20:06:21 -0700 Subject: [PATCH 2/5] new notifiers package, easier to make your own notifier --- cli.go | 13 ---- core/communication.go | 96 ------------------------ core/core.go | 13 +--- core/events.go | 40 +--------- core/setup.go | 22 ------ handlers/routes.go | 3 +- handlers/settings.go | 101 +++++++++++++------------ main_test.go | 5 +- notifiers/email.go | 151 ++++++++++++++++++++++++++++++++++++++ notifiers/email_old.go | 105 -------------------------- notifiers/notifiers.go | 87 ++++++++++++++++++++-- notifiers/slack.go | 50 ++++++++++--- notifiers/structs.go | 1 - source/tmpl/settings.html | 72 ++---------------- 14 files changed, 334 insertions(+), 425 deletions(-) delete mode 100644 core/communication.go create mode 100644 notifiers/email.go delete mode 100644 notifiers/email_old.go delete mode 100644 notifiers/structs.go diff --git a/cli.go b/cli.go index 2103accb..cef480c8 100644 --- a/cli.go +++ b/cli.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "github.com/hunterlong/statup/core" - "github.com/hunterlong/statup/notifiers" "github.com/hunterlong/statup/plugin" "github.com/hunterlong/statup/utils" "github.com/joho/godotenv" @@ -246,18 +245,6 @@ func FakeSeed(plug plugin.PluginActions) { } fakeUser.Create() - comm := ¬ifiers.Notification{ - Id: 1, - Method: "email", - } - core.Create(comm) - - comm2 := ¬ifiers.Notification{ - Id: 2, - Method: "slack", - } - core.Create(comm2) - for i := 0; i <= 50; i++ { dd := core.HitData{ Latency: rand.Float64(), diff --git a/core/communication.go b/core/communication.go deleted file mode 100644 index 1cf7872f..00000000 --- a/core/communication.go +++ /dev/null @@ -1,96 +0,0 @@ -package core - -import ( - "github.com/hunterlong/statup/notifiers" - "github.com/hunterlong/statup/utils" -) - -func LoadDefaultCommunications() { - //communications.EmailComm = SelectCommunication(1) - //emailer := communications.EmailComm - //if emailer.Enabled { - // admin, _ := SelectUser(1) - // communications.LoadEmailer(emailer) - // email := &types.Email{ - // To: admin.Email, - // Subject: "Test Email", - // Template: "message.html", - // Data: nil, - // From: emailer.Var1, - // } - // communications.SendEmail(EmailBox, email) - // go communications.EmailRoutine() - //} - //communications.SlackComm = SelectCommunication(2) - //slack := communications.SlackComm - //if slack.Enabled { - // communications.LoadSlack(slack.Host) - // msg := fmt.Sprintf("Slack loaded on your Statup Status Page!") - // communications.SendSlack(msg) - // go communications.SlackRoutine() - //} -} - -func LoadComms() { - for _, c := range CoreApp.Communications { - if c.Enabled { - - } - } -} - -func SelectAllCommunications() ([]*notifiers.Notification, error) { - var c []*notifiers.Notification - col := DbSession.Collection("communication").Find() - err := col.OrderBy("id").All(&c) - //CoreApp.Communications = c - //communications.LoadComms(c) - return c, err -} - -func Create(c *notifiers.Notification) (int64, error) { - //c.CreatedAt = time.Now() - //uuid, err := DbSession.Collection("communication").Insert(c) - //if err != nil { - // utils.Log(3, err) - //} - //if uuid == nil { - // utils.Log(2, err) - // return 0, err - //} - //c.Id = uuid.(int64) - //c.Routine = make(chan struct{}) - //if CoreApp != nil { - // CoreApp.Communications = append(CoreApp.Communications, c.Communicator) - //} - //return uuid.(int64), err - return 0, nil -} - -func Disable(c *notifiers.Notification) { - c.Enabled = false - Update(c) -} - -func Enable(c *notifiers.Notification) { - c.Enabled = true - Update(c) -} - -func Update(c *notifiers.Notification) *notifiers.Notification { - col := DbSession.Collection("communication").Find("id", c.Id) - col.Update(c) - SelectAllCommunications() - return c -} - -func SelectCommunication(id int64) *notifiers.Notification { - var comm *notifiers.Notification - col := DbSession.Collection("communication").Find("id", id) - err := col.One(&comm) - if err != nil { - utils.Log(2, err) - return nil - } - return comm -} diff --git a/core/core.go b/core/core.go index 1d149efc..72c112bd 100644 --- a/core/core.go +++ b/core/core.go @@ -29,7 +29,7 @@ type Core struct { Plugins []plugin.Info Repos []PluginJSON AllPlugins []plugin.PluginActions - Communications []*notifiers.Notification + Communications []notifiers.AllNotifiers DbConnection string started time.Time } @@ -60,19 +60,10 @@ func NewCore() *Core { func InitApp() { SelectCore() - notifiers.Collections = DbSession.Collection("communication") - - SelectAllCommunications() - InsertDefaultComms() - LoadDefaultCommunications() SelectAllServices() CheckServices() - - notifiers.Load() - - CoreApp.Communications = notifiers.AllCommunications - + CoreApp.Communications = notifiers.Load() go DatabaseMaintence() } diff --git a/core/events.go b/core/events.go index aa4c919a..df27fcc0 100644 --- a/core/events.go +++ b/core/events.go @@ -1,11 +1,9 @@ package core import ( - "fmt" "github.com/fatih/structs" "github.com/hunterlong/statup/notifiers" "github.com/hunterlong/statup/plugin" - "github.com/hunterlong/statup/types" "upper.io/db.v3/lib/sqlbuilder" ) @@ -19,48 +17,14 @@ func OnSuccess(s *Service) { for _, p := range CoreApp.AllPlugins { p.OnSuccess(structs.Map(s)) } + notifiers.OnSuccess() } func OnFailure(s *Service, f FailureData) { for _, p := range CoreApp.AllPlugins { p.OnFailure(structs.Map(s)) } - if notifiers.SendSlack("im failing") != nil { - onFailureSlack(s, f) - } - if notifiers.EmailComm != nil { - onFailureEmail(s, f) - } -} - -func onFailureSlack(s *Service, f FailureData) { - slack := SelectCommunication(2) - if slack.Enabled { - //msg := fmt.Sprintf("Service %v is currently offline! Issue: %v", s.Name, f.Issue) - //communications.SendSlack(msg) - } -} - -type failedEmail struct { - Service *Service - FailureData FailureData - Domain string -} - -func onFailureEmail(s *Service, f FailureData) { - email := SelectCommunication(1) - if email.Enabled { - data := failedEmail{s, f, CoreApp.Domain} - admin, _ := SelectUser(1) - email := &types.Email{ - To: admin.Email, - Subject: fmt.Sprintf("Service %v is Down", s.Name), - Template: "failure.html", - Data: data, - From: email.Var1, - } - notifiers.SendEmail(EmailBox, email) - } + notifiers.OnFailure() } func OnSettingsSaved(c *Core) { diff --git a/core/setup.go b/core/setup.go index 38f14052..e3840151 100644 --- a/core/setup.go +++ b/core/setup.go @@ -2,32 +2,10 @@ package core import ( "fmt" - "github.com/hunterlong/statup/notifiers" "github.com/hunterlong/statup/utils" "os" ) -func InsertDefaultComms() { - emailer := SelectCommunication(1) - if emailer == nil { - emailer := ¬ifiers.Notification{ - Method: "email", - Removable: false, - Enabled: false, - } - Create(emailer) - } - slack := SelectCommunication(2) - if slack == nil { - slack := ¬ifiers.Notification{ - Method: "slack", - Removable: false, - Enabled: false, - } - Create(slack) - } -} - func DeleteConfig() { err := os.Remove("./config.yml") if err != nil { diff --git a/handlers/routes.go b/handlers/routes.go index 42476c54..207f1fa3 100644 --- a/handlers/routes.go +++ b/handlers/routes.go @@ -37,8 +37,7 @@ func Router() *mux.Router { r.Handle("/settings", http.HandlerFunc(SaveSettingsHandler)).Methods("POST") r.Handle("/settings/css", http.HandlerFunc(SaveSASSHandler)).Methods("POST") r.Handle("/settings/build", http.HandlerFunc(SaveAssetsHandler)).Methods("GET") - r.Handle("/settings/email", http.HandlerFunc(SaveEmailSettingsHandler)).Methods("POST") - r.Handle("/settings/slack", http.HandlerFunc(SaveSlackSettingsHandler)).Methods("POST") + r.Handle("/settings/notifier_{{id}}", http.HandlerFunc(SaveNotificationHandler)).Methods("POST") r.Handle("/plugins/download/{name}", http.HandlerFunc(PluginsDownloadHandler)) r.Handle("/plugins/{name}/save", http.HandlerFunc(PluginSavedHandler)).Methods("POST") r.Handle("/help", http.HandlerFunc(HelpHandler)) diff --git a/handlers/settings.go b/handlers/settings.go index 8a19650d..0b49a663 100644 --- a/handlers/settings.go +++ b/handlers/settings.go @@ -1,9 +1,9 @@ package handlers import ( + "fmt" "github.com/hunterlong/statup/core" "github.com/hunterlong/statup/notifiers" - "github.com/hunterlong/statup/types" "github.com/hunterlong/statup/utils" "net/http" ) @@ -84,65 +84,62 @@ func SaveAssetsHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/settings", http.StatusSeeOther) } -func SaveEmailSettingsHandler(w http.ResponseWriter, r *http.Request) { +func SaveNotificationHandler(w http.ResponseWriter, r *http.Request) { if !IsAuthenticated(r) { http.Redirect(w, r, "/", http.StatusSeeOther) return } - emailer := core.SelectCommunication(1) r.ParseForm() - smtpHost := r.PostForm.Get("host") - smtpUser := r.PostForm.Get("username") - smtpPass := r.PostForm.Get("password") - smtpPort := int(utils.StringInt(r.PostForm.Get("port"))) - smtpOutgoing := r.PostForm.Get("address") - enabled := r.PostForm.Get("enable_email") - emailer.Host = smtpHost - emailer.Username = smtpUser - if smtpPass != "#######################" { - emailer.Password = smtpPass + notifierId := r.PostForm.Get("id") + enabled := r.PostForm.Get("enable") + + host := r.PostForm.Get("host") + port := int(utils.StringInt(r.PostForm.Get("port"))) + username := r.PostForm.Get("username") + password := r.PostForm.Get("password") + var1 := r.PostForm.Get("var1") + var2 := r.PostForm.Get("var2") + apiKey := r.PostForm.Get("api_key") + apiSecret := r.PostForm.Get("api_secret") + limits := int64(utils.StringInt(r.PostForm.Get("limits"))) + notifer := notifiers.Select(utils.StringInt(notifierId)) + if host != "" { + notifer.Host = host + } + if port != 0 { + notifer.Port = port + } + if username != "" { + notifer.Username = username + } + if password != "" && password != "##########" { + notifer.Password = password + } + if var1 != "" { + notifer.Var1 = var1 + } + if var2 != "" { + notifer.Var2 = var2 + } + if apiKey != "" { + notifer.ApiKey = apiKey + } + if apiSecret != "" { + notifer.ApiSecret = apiSecret + } + if limits != 0 { + notifer.Limits = limits } - emailer.Port = smtpPort - emailer.Var1 = smtpOutgoing - emailer.Enabled = false if enabled == "on" { - emailer.Enabled = true + notifer.Enabled = true + } else { + notifer.Enabled = false } - core.Update(emailer) - - sample := &types.Email{ - To: SessionUser(r).Email, - Subject: "Test Email", - Template: "message.html", - From: emailer.Var1, + notifer, err := notifer.Update() + if err != nil { + utils.Log(3, err) } - notifiers.LoadEmailer(emailer) - notifiers.SendEmail(core.EmailBox, sample) - notifiers.EmailComm = emailer - if emailer.Enabled { - utils.Log(1, "Starting Email Routine, 1 unique email per 60 seconds") - go notifiers.EmailRoutine() - } - - http.Redirect(w, r, "/settings", http.StatusSeeOther) -} - -func SaveSlackSettingsHandler(w http.ResponseWriter, r *http.Request) { - if !IsAuthenticated(r) { - http.Redirect(w, r, "/", http.StatusSeeOther) - return - } - slack := core.SelectCommunication(2) - r.ParseForm() - slackWebhook := r.PostForm.Get("slack_url") - enable := r.PostForm.Get("enable_slack") - slack.Enabled = false - if enable == "on" && slackWebhook != "" { - slack.Enabled = true - //go communications.SlackRoutine() - } - slack.Host = slackWebhook - core.Update(slack) - http.Redirect(w, r, "/settings", http.StatusSeeOther) + msg := fmt.Sprintf("%v - %v - %v", notifierId, notifer, enabled) + w.Write([]byte(msg)) } diff --git a/main_test.go b/main_test.go index f93064e6..9a531954 100644 --- a/main_test.go +++ b/main_test.go @@ -5,6 +5,7 @@ import ( "github.com/gorilla/sessions" "github.com/hunterlong/statup/core" "github.com/hunterlong/statup/handlers" + "github.com/hunterlong/statup/notifiers" "github.com/rendon/testcli" "github.com/stretchr/testify/assert" "net/http" @@ -218,7 +219,6 @@ func RunMySQLMakeConfig(t *testing.T, db string) { err = core.DbConnection(core.Configs.Connection) assert.Nil(t, err) - core.InsertDefaultComms() } func RunInsertMysqlSample(t *testing.T) { @@ -254,7 +254,8 @@ func RunSelectAllMysqlServices(t *testing.T) { func RunSelectAllMysqlCommunications(t *testing.T) { var err error - comms, err := core.SelectAllCommunications() + notifiers.Collections = core.DbSession.Collection("communication") + comms := notifiers.Load() assert.Nil(t, err) assert.Equal(t, 2, len(comms)) } diff --git a/notifiers/email.go b/notifiers/email.go new file mode 100644 index 00000000..29533515 --- /dev/null +++ b/notifiers/email.go @@ -0,0 +1,151 @@ +package notifiers + +import ( + "fmt" + "github.com/hunterlong/statup/utils" + "time" +) + +const ( + EMAIL_ID int64 = 1 + EMAIL_METHOD = "email" +) + +var ( + emailer *Email + emailArray []string +) + +type Email struct { + *Notification +} + +// DEFINE YOUR NOTIFICATION HERE. +func init() { + + emailer = &Email{&Notification{ + Id: EMAIL_ID, + Method: EMAIL_METHOD, + Form: []NotificationForm{{ + id: 1, + Type: "text", + Title: "SMTP Host", + Placeholder: "Insert your SMTP Host here.", + DbField: "Host", + }, { + id: 1, + Type: "text", + Title: "SMTP Username", + Placeholder: "Insert your SMTP Username here.", + DbField: "Username", + }, { + id: 1, + Type: "password", + Title: "SMTP Password", + Placeholder: "Insert your SMTP Password here.", + DbField: "Password", + }, { + id: 1, + Type: "number", + Title: "SMTP Port", + Placeholder: "Insert your SMTP Port here.", + DbField: "Port", + }, { + id: 1, + Type: "text", + Title: "Outgoing Email Address", + Placeholder: "Insert your Outgoing Email Address", + DbField: "Var1", + }, { + id: 1, + Type: "number", + Title: "Limits per Hour", + Placeholder: "How many emails can it send per hour", + DbField: "Limits", + }}, + }} + + add(emailer) +} + +// Select Obj +func (u *Email) Select() *Notification { + return u.Notification +} + +// WHEN NOTIFIER LOADS +func (u *Email) Init() error { + //err := SendSlack("its online") + + u.Install() + + //go u.Run() + return nil +} + +// AFTER NOTIFIER LOADS, IF ENABLED, START A QUEUE PROCESS +func (u *Email) Run() error { + //var sentAddresses []string + //for _, email := range emailArray { + // if inArray(sentAddresses, email.To) || email.Sent { + // emailQueue = removeEmail(emailQueue, email) + // continue + // } + // e := email + // go func(email *types.Email) { + // err := dialSend(email) + // if err == nil { + // email.Sent = true + // sentAddresses = append(sentAddresses, email.To) + // utils.Log(1, fmt.Sprintf("Email '%v' sent to: %v using the %v template (size: %v)", email.Subject, email.To, email.Template, len([]byte(email.Source)))) + // emailQueue = removeEmail(emailQueue, email) + // } + // }(e) + //} + time.Sleep(60 * time.Second) + //if EmailComm.Enabled { + //EmailRoutine() + //} + return nil +} + +// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS +func (u *Email) OnFailure() error { + utils.Log(1, fmt.Sprintf("Notification %v is receiving a failure notification.", u.Method)) + + // Do failing stuff here! + + return nil +} + +// ON SERVICE SUCCESS, DO YOUR OWN FUNCTIONS +func (u *Email) OnSuccess() error { + utils.Log(1, fmt.Sprintf("Notification %v is receiving a successful notification.", u.Method)) + + // Do checking or any successful things here + + return nil +} + +// ON SAVE OR UPDATE OF THE NOTIFIER FORM +func (u *Email) OnSave() error { + utils.Log(1, fmt.Sprintf("Notification %v is receiving updated information.", u.Method)) + + // Do updating stuff here + + return nil +} + +// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS +func (u *Email) Install() error { + inDb, err := emailer.Notification.isInDatabase() + if !inDb { + newNotifer, err := InsertDatabase(u.Notification) + if err != nil { + utils.Log(3, err) + return err + } + utils.Log(1, fmt.Sprintf("new notifier #%v installed: %v", newNotifer, u.Method)) + } + return err +} diff --git a/notifiers/email_old.go b/notifiers/email_old.go deleted file mode 100644 index 5db3b99e..00000000 --- a/notifiers/email_old.go +++ /dev/null @@ -1,105 +0,0 @@ -package notifiers - -import ( - "bytes" - "crypto/tls" - "fmt" - "github.com/GeertJohan/go.rice" - "github.com/hunterlong/statup/types" - "github.com/hunterlong/statup/utils" - "gopkg.in/gomail.v2" - "html/template" - "time" -) - -var ( - mailer *gomail.Dialer - emailQueue []*types.Email - EmailComm *Notification -) - -func EmailRoutine() { - var sentAddresses []string - for _, email := range emailQueue { - if inArray(sentAddresses, email.To) || email.Sent { - emailQueue = removeEmail(emailQueue, email) - continue - } - e := email - go func(email *types.Email) { - err := dialSend(email) - if err == nil { - email.Sent = true - sentAddresses = append(sentAddresses, email.To) - utils.Log(1, fmt.Sprintf("Email '%v' sent to: %v using the %v template (size: %v)", email.Subject, email.To, email.Template, len([]byte(email.Source)))) - emailQueue = removeEmail(emailQueue, email) - } - }(e) - } - time.Sleep(60 * time.Second) - if EmailComm.Enabled { - EmailRoutine() - } -} - -func dialSend(email *types.Email) error { - m := gomail.NewMessage() - 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(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)) - return err - } - return nil -} - -func LoadEmailer(mail *Notification) { - utils.Log(1, fmt.Sprintf("Loading SMTP Emailer using host: %v:%v", mail.Host, mail.Port)) - mailer = gomail.NewDialer(mail.Host, mail.Port, mail.Username, mail.Password) - mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true} -} - -func SendEmail(box *rice.Box, email *types.Email) { - source := EmailTemplate(box, email.Template, email.Data) - email.Source = source - emailQueue = append(emailQueue, email) -} - -func EmailTemplate(box *rice.Box, tmpl string, data interface{}) string { - emailTpl, err := box.String(tmpl) - if err != nil { - utils.Log(3, err) - } - t := template.New("email") - t, err = t.Parse(emailTpl) - 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 -} - -func removeEmail(emails []*types.Email, em *types.Email) []*types.Email { - var newArr []*types.Email - for _, e := range emails { - if e != em { - newArr = append(newArr, e) - } - } - return newArr -} - -func inArray(a []string, v string) bool { - for _, i := range a { - if i == v { - return true - } - } - return false -} diff --git a/notifiers/notifiers.go b/notifiers/notifiers.go index 343aea42..18550efd 100644 --- a/notifiers/notifiers.go +++ b/notifiers/notifiers.go @@ -1,25 +1,33 @@ package notifiers import ( + "fmt" "github.com/hunterlong/statup/utils" + "strings" "time" "upper.io/db.v3" ) var ( - AllCommunications []*Notification + AllCommunications []AllNotifiers Collections db.Collection ) -func add(c *Notification) { +type AllNotifiers interface{} + +func add(c interface{}) { AllCommunications = append(AllCommunications, c) } -func Load() { +func Load() []AllNotifiers { utils.Log(1, "Loading notifiers") + var notifiers []AllNotifiers for _, comm := range AllCommunications { - comm.Init() + n := comm.(Notifier) + n.Init() + notifiers = append(notifiers, n) } + return notifiers } type Notification struct { @@ -43,26 +51,93 @@ type Notification struct { type Notifier interface { Init() error + Install() error Run() error OnFailure() error OnSuccess() error + Select() *Notification } type NotificationForm struct { + id int64 Type string Title string Placeholder string + DbField string +} + +func (n *Notification) isInDatabase() (bool, error) { + return Collections.Find("id", n.Id).Exists() +} + +func (n *Notification) Update() (*Notification, error) { + n.CreatedAt = time.Now() + err := Collections.Find("id", n.Id).Update(n) + return n, err +} + +func InsertDatabase(n *Notification) (int64, error) { + n.CreatedAt = time.Now() + newId, err := Collections.Insert(n) + if err != nil { + return 0, err + } + return newId.(int64), err +} + +func Select(id int64) *Notification { + var notifier *Notification + for _, n := range AllCommunications { + notif := n.(Notifier) + notifier = notif.Select() + if notifier.Id == id { + return notifier + } + } + return notifier +} + +func (f NotificationForm) Value() string { + notifier := Select(f.id) + return notifier.GetValue(f.DbField) +} + +func (n *Notification) GetValue(dbField string) string { + dbField = strings.ToLower(dbField) + switch dbField { + case "host": + return n.Host + case "port": + return fmt.Sprintf("%v", n.Port) + case "username": + return n.Username + case "password": + if n.Password != "" { + return "##########" + } + case "var1": + return n.Var1 + case "var2": + return n.Var2 + case "api_key": + return n.ApiKey + case "api_secret": + return n.ApiSecret + } + return "" } func OnFailure() { for _, comm := range AllCommunications { - comm.OnFailure() + n := comm.(Notifier) + n.OnFailure() } } func OnSuccess() { for _, comm := range AllCommunications { - comm.OnSuccess() + n := comm.(Notifier) + n.OnSuccess() } } diff --git a/notifiers/slack.go b/notifiers/slack.go index 783ec229..a8d94132 100644 --- a/notifiers/slack.go +++ b/notifiers/slack.go @@ -9,39 +9,53 @@ import ( ) const ( - SLACK_ID int64 = 2 - SLACK_METHOD = "slack" + SLACK_ID = 2 + SLACK_METHOD = "slack" ) var ( - slacker *Notification + slacker *Slack slackMessages []string ) +type Slack struct { + *Notification +} + // DEFINE YOUR NOTIFICATION HERE. func init() { - slacker = &Notification{ + slacker = &Slack{&Notification{ Id: SLACK_ID, Method: SLACK_METHOD, Host: "https://webhooksurl.slack.com/***", Form: []NotificationForm{{ + id: 2, Type: "text", Title: "Incoming Webhook Url", Placeholder: "Insert your Slack webhook URL here.", - }}, + DbField: "Host", + }}}, } add(slacker) } +// Select Obj +func (u *Slack) Select() *Notification { + return u.Notification +} + // WHEN NOTIFIER LOADS -func (u *Notification) Init() error { +func (u *Slack) Init() error { err := SendSlack("its online") - go u.Run() + + u.Install() + + //go u.Run() return err } // AFTER NOTIFIER LOADS, IF ENABLED, START A QUEUE PROCESS -func (u *Notification) Run() error { +func (u *Slack) Run() error { for _, msg := range slackMessages { utils.Log(1, fmt.Sprintf("Sending JSON to Slack Webhook: %v", msg)) client := http.Client{Timeout: 15 * time.Second} @@ -69,7 +83,7 @@ func SendSlack(msg string) error { } // ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS -func (u *Notification) OnFailure() error { +func (u *Slack) OnFailure() error { utils.Log(1, fmt.Sprintf("Notification %v is receiving a failure notification.", u.Method)) // Do failing stuff here! @@ -78,7 +92,7 @@ func (u *Notification) OnFailure() error { } // ON SERVICE SUCCESS, DO YOUR OWN FUNCTIONS -func (u *Notification) OnSuccess() error { +func (u *Slack) OnSuccess() error { utils.Log(1, fmt.Sprintf("Notification %v is receiving a successful notification.", u.Method)) // Do checking or any successful things here @@ -87,10 +101,24 @@ func (u *Notification) OnSuccess() error { } // ON SAVE OR UPDATE OF THE NOTIFIER FORM -func (u *Notification) OnSave() error { +func (u *Slack) OnSave() error { utils.Log(1, fmt.Sprintf("Notification %v is receiving updated information.", u.Method)) // Do updating stuff here return nil } + +// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS +func (u *Slack) Install() error { + inDb, err := slacker.Notification.isInDatabase() + if !inDb { + newNotifer, err := InsertDatabase(u.Notification) + if err != nil { + utils.Log(3, err) + return err + } + utils.Log(1, fmt.Sprintf("new notifier #%v installed: %v", newNotifer, u.Method)) + } + return err +} diff --git a/notifiers/structs.go b/notifiers/structs.go deleted file mode 100644 index 48b634c4..00000000 --- a/notifiers/structs.go +++ /dev/null @@ -1 +0,0 @@ -package notifiers diff --git a/source/tmpl/settings.html b/source/tmpl/settings.html index b2df7958..42ffc267 100644 --- a/source/tmpl/settings.html +++ b/source/tmpl/settings.html @@ -32,12 +32,9 @@