diff --git a/.travis.yml b/.travis.yml
index ae717ce6..fcc62ea1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,7 +18,7 @@ services:
env:
global:
- - VERSION=0.29.8
+ - VERSION=0.29.9
- DB_HOST=localhost
- DB_USER=travis
- DB_PASS=
diff --git a/Dockerfile b/Dockerfile
index 316d0aca..b8d18201 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
FROM alpine:latest
-ENV VERSION=v0.29.8
+ENV VERSION=v0.29.9
RUN apk --no-cache add libstdc++ ca-certificates
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \
diff --git a/cli.go b/cli.go
index 125438f8..cef480c8 100644
--- a/cli.go
+++ b/cli.go
@@ -5,7 +5,6 @@ import (
"fmt"
"github.com/hunterlong/statup/core"
"github.com/hunterlong/statup/plugin"
- "github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils"
"github.com/joho/godotenv"
"io/ioutil"
@@ -246,18 +245,6 @@ func FakeSeed(plug plugin.PluginActions) {
}
fakeUser.Create()
- comm := &types.Communication{
- Id: 1,
- Method: "email",
- }
- core.Create(comm)
-
- comm2 := &types.Communication{
- 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 9bccb2f6..00000000
--- a/core/communication.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package core
-
-import (
- "fmt"
- "github.com/hunterlong/statup/notifications"
- "github.com/hunterlong/statup/types"
- "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()
- }
-}
-
-func LoadComms() {
- for _, c := range CoreApp.Communications {
- if c.Enabled {
-
- }
- }
-}
-
-func SelectAllCommunications() ([]*types.Communication, error) {
- var c []*types.Communication
- col := DbSession.Collection("communication").Find()
- err := col.OrderBy("id").All(&c)
- CoreApp.Communications = 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 Disable(c *types.Communication) {
- c.Enabled = false
- Update(c)
-}
-
-func Enable(c *types.Communication) {
- c.Enabled = true
- Update(c)
-}
-
-func Update(c *types.Communication) *types.Communication {
- col := DbSession.Collection("communication").Find("id", c.Id)
- col.Update(c)
- SelectAllCommunications()
- return c
-}
-
-func SelectCommunication(id int64) *types.Communication {
- var comm *types.Communication
- 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/configs.go b/core/configs.go
index 8f4c5a77..bcee6837 100644
--- a/core/configs.go
+++ b/core/configs.go
@@ -2,14 +2,19 @@ package core
import (
"errors"
+ "fmt"
"github.com/go-yaml/yaml"
"github.com/hunterlong/statup/types"
+ "github.com/hunterlong/statup/utils"
"io/ioutil"
"os"
+ "time"
)
func LoadConfig() (*types.Config, error) {
if os.Getenv("DB_CONN") != "" {
+ utils.Log(1, "DB_CONN environment variable was found")
+ //time.Sleep(20 * time.Second)
return LoadUsingEnv()
}
Configs = new(types.Config)
@@ -51,12 +56,65 @@ func LoadUsingEnv() (*types.Config, error) {
if os.Getenv("USE_CDN") == "true" {
CoreApp.UseCdn = true
}
+
+ dbConfig := &DbConfig{
+ DbConn: os.Getenv("DB_CONN"),
+ DbHost: os.Getenv("DB_HOST"),
+ DbUser: os.Getenv("DB_USER"),
+ DbPass: os.Getenv("DB_PASS"),
+ DbData: os.Getenv("DB_DATABASE"),
+ DbPort: 5432,
+ Project: "Statup - " + os.Getenv("NAME"),
+ Description: "New Statup Installation",
+ Domain: os.Getenv("DOMAIN"),
+ Username: "admin",
+ Password: "admin",
+ Email: "info@localhost.com",
+ }
+
+ err := DbConnection(dbConfig.DbConn)
+ if err != nil {
+ utils.Log(4, err)
+ return nil, err
+ }
+
+ exists, err := DbSession.Collection("core").Find().Exists()
+ if !exists {
+
+ utils.Log(1, fmt.Sprintf("Core database does not exist, creating now!"))
+ DropDatabase()
+ CreateDatabase()
+
+ CoreApp = &Core{
+ Name: dbConfig.Project,
+ Description: dbConfig.Description,
+ Config: "config.yml",
+ ApiKey: utils.NewSHA1Hash(9),
+ ApiSecret: utils.NewSHA1Hash(16),
+ Domain: dbConfig.Domain,
+ MigrationId: time.Now().Unix(),
+ }
+
+ CoreApp.DbConnection = dbConfig.DbConn
+
+ err := CoreApp.Insert()
+ if err != nil {
+ utils.Log(3, err)
+ }
+
+ admin := &User{
+ Username: "admin",
+ Password: "admin",
+ Email: "info@admin.com",
+ Admin: true,
+ }
+ admin.Create()
+
+ LoadSampleData()
+
+ return Configs, err
+
+ }
+
return Configs, nil
}
-
-func ifOr(val, def string) string {
- if val == "" {
- return def
- }
- return val
-}
diff --git a/core/core.go b/core/core.go
index d6804229..84bec322 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.AllNotifiers
DbConnection string
started time.Time
}
@@ -57,13 +58,18 @@ func NewCore() *Core {
return CoreApp
}
+func (c *Core) Insert() error {
+ col := DbSession.Collection("core")
+ _, err := col.Insert(c)
+ return err
+}
+
func InitApp() {
SelectCore()
- SelectAllCommunications()
- InsertDefaultComms()
- LoadDefaultCommunications()
+ notifiers.Collections = DbSession.Collection("communication")
SelectAllServices()
CheckServices()
+ CoreApp.Communications = notifiers.Load()
go DatabaseMaintence()
}
@@ -121,6 +127,11 @@ func SelectLastMigration() (int64, error) {
func SelectCore() (*Core, error) {
var c *Core
+ exists := DbSession.Collection("core").Exists()
+ if !exists {
+ return nil, errors.New("core database has not been setup yet.")
+ }
+
err := DbSession.Collection("core").Find().One(&c)
if err != nil {
return nil, err
diff --git a/core/database.go b/core/database.go
index 40e0df5a..1aecfc01 100644
--- a/core/database.go
+++ b/core/database.go
@@ -135,6 +135,9 @@ func (c *DbConfig) Save() error {
}
CoreApp, err = SelectCore()
+ if err != nil {
+ utils.Log(4, err)
+ }
CoreApp.DbConnection = c.DbConn
return err
@@ -207,7 +210,7 @@ func RunDatabaseUpgrades() error {
}
func DropDatabase() {
- fmt.Println("Dropping Tables...")
+ utils.Log(1, "Dropping Database Tables...")
down, _ := SqlBox.String("down.sql")
requests := strings.Split(down, ";")
for _, request := range requests {
@@ -219,7 +222,7 @@ func DropDatabase() {
}
func CreateDatabase() {
- fmt.Println("Creating Tables...")
+ utils.Log(1, "Creating Database Tables...")
sql := "postgres_up.sql"
if CoreApp.DbConnection == "mysql" {
sql = "mysql_up.sql"
@@ -236,7 +239,7 @@ func CreateDatabase() {
}
//secret := NewSHA1Hash()
//db.QueryRow("INSERT INTO core (secret, version) VALUES ($1, $2);", secret, VERSION).Scan()
- fmt.Println("Database Created")
+ utils.Log(1, "Database Created")
//SampleData()
}
diff --git a/core/events.go b/core/events.go
index 29796333..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/notifications"
+ "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 notifications.SlackComm != nil {
- onFailureSlack(s, f)
- }
- if notifications.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)
- notifications.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,
- }
- notifications.SendEmail(EmailBox, email)
- }
+ notifiers.OnFailure()
}
func OnSettingsSaved(c *Core) {
diff --git a/core/services.go b/core/services.go
index 815ed836..d763ea99 100644
--- a/core/services.go
+++ b/core/services.go
@@ -58,6 +58,7 @@ func SelectAllServices() ([]*Service, error) {
err := col.All(&srvcs)
if err != nil {
utils.Log(3, err)
+ return nil, err
}
for _, s := range srvcs {
s.Checkins = s.SelectAllCheckins()
diff --git a/core/setup.go b/core/setup.go
index f81bde73..841ca1f9 100644
--- a/core/setup.go
+++ b/core/setup.go
@@ -2,32 +2,10 @@ package core
import (
"fmt"
- "github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils"
"os"
)
-func InsertDefaultComms() {
- emailer := SelectCommunication(1)
- if emailer == nil {
- emailer := &types.Communication{
- Method: "email",
- Removable: false,
- Enabled: false,
- }
- Create(emailer)
- }
- slack := SelectCommunication(2)
- if slack == nil {
- slack := &types.Communication{
- Method: "slack",
- Removable: false,
- Enabled: false,
- }
- Create(slack)
- }
-}
-
func DeleteConfig() {
err := os.Remove("./config.yml")
if err != nil {
@@ -95,15 +73,15 @@ func LoadSampleData() error {
utils.Log(3, fmt.Sprintf("Error creating Service %v: %v", id, err))
}
- checkin := &Checkin{
- Service: s2.Id,
- Interval: 30,
- Api: utils.NewSHA1Hash(18),
- }
- id, err = checkin.Create()
- if err != nil {
- utils.Log(3, fmt.Sprintf("Error creating Checkin %v: %v", id, err))
- }
+ //checkin := &Checkin{
+ // Service: s2.Id,
+ // Interval: 30,
+ // Api: utils.NewSHA1Hash(18),
+ //}
+ //id, err = checkin.Create()
+ //if err != nil {
+ // utils.Log(3, fmt.Sprintf("Error creating Checkin %v: %v", id, err))
+ //}
//for i := 0; i < 3; i++ {
// s1.Check()
diff --git a/handlers/routes.go b/handlers/routes.go
index 42476c54..873afe43 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 f95d95ec..59951b21 100644
--- a/handlers/settings.go
+++ b/handlers/settings.go
@@ -1,9 +1,10 @@
package handlers
import (
+ "fmt"
+ "github.com/gorilla/mux"
"github.com/hunterlong/statup/core"
- "github.com/hunterlong/statup/notifications"
- "github.com/hunterlong/statup/types"
+ "github.com/hunterlong/statup/notifiers"
"github.com/hunterlong/statup/utils"
"net/http"
)
@@ -84,65 +85,72 @@ 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) {
+ var err error
if !IsAuthenticated(r) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
- emailer := core.SelectCommunication(1)
+ vars := mux.Vars(r)
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 := vars["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
+ }
+ notifer, err = notifer.Update()
+ if err != nil {
+ utils.Log(3, err)
}
- core.Update(emailer)
- sample := &types.Email{
- To: SessionUser(r).Email,
- Subject: "Test Email",
- Template: "message.html",
- From: emailer.Var1,
- }
- notifications.LoadEmailer(emailer)
- notifications.SendEmail(core.EmailBox, sample)
- notifications.EmailComm = emailer
- if emailer.Enabled {
- utils.Log(1, "Starting Email Routine, 1 unique email per 60 seconds")
- go notifications.EmailRoutine()
+ if notifer.Enabled {
+ notify := notifiers.SelectNotifier(notifer.Id)
+ go notify.Run()
}
+ utils.Log(1, fmt.Sprintf("Notifier saved: %v", notifer))
+
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 notifications.SlackRoutine()
- }
- slack.Host = slackWebhook
- core.Update(slack)
- http.Redirect(w, r, "/settings", http.StatusSeeOther)
-}
diff --git a/main.go b/main.go
index eaa305f3..cdc76b76 100644
--- a/main.go
+++ b/main.go
@@ -65,7 +65,7 @@ func mainProcess() {
var err error
err = core.DbConnection(core.Configs.Connection)
if err != nil {
- utils.Log(3, err)
+ utils.Log(4, fmt.Sprintf("could not connect to database: %v", err))
}
core.RunDatabaseUpgrades()
diff --git a/main_test.go b/main_test.go
index f93064e6..40256ddc 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))
}
@@ -533,7 +534,6 @@ func RunSettingsHandler(t *testing.T) {
route.ServeHTTP(rr, req)
assert.True(t, strings.Contains(rr.Body.String(), "
Statup | Settings"))
assert.True(t, strings.Contains(rr.Body.String(), "Theme Editor"))
- assert.True(t, strings.Contains(rr.Body.String(), "Email Settings"))
assert.True(t, strings.Contains(rr.Body.String(), "footer"))
}
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/email.go b/notifications/email.go
deleted file mode 100644
index 49001ee5..00000000
--- a/notifications/email.go
+++ /dev/null
@@ -1,105 +0,0 @@
-package notifications
-
-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 *types.Communication
-)
-
-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 *types.Communication) {
- 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/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/notifiers/email.go b/notifiers/email.go
new file mode 100644
index 00000000..ab9631c0
--- /dev/null
+++ b/notifiers/email.go
@@ -0,0 +1,241 @@
+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"
+)
+
+const (
+ EMAIL_ID int64 = 1
+ EMAIL_METHOD = "email"
+)
+
+var (
+ emailer *Email
+ emailArray []string
+ emailQueue []*types.Email
+)
+
+type Email struct {
+ *Notification
+ mailer *gomail.Dialer
+}
+
+// DEFINE YOUR NOTIFICATION HERE.
+func init() {
+
+ emailer = &Email{
+ Notification: &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 := u.Install()
+
+ if err == nil {
+ notifier, _ := SelectNotification(u.Id)
+ forms := u.Form
+ u.Notification = notifier
+ u.Form = forms
+ if u.Enabled {
+
+ utils.Log(1, fmt.Sprintf("Loading SMTP Emailer using host: %v:%v", u.Notification.Host, u.Notification.Port))
+ u.mailer = gomail.NewDialer(u.Notification.Host, u.Notification.Port, u.Notification.Username, u.Notification.Password)
+ u.mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
+
+ go u.Run()
+ }
+ }
+
+ //go u.Run()
+ return nil
+}
+
+func (u *Email) Test() error {
+ //email := &types.Email{
+ // To: "info@socialeck.com",
+ // Subject: "Test Email",
+ // Template: "message.html",
+ // Data: nil,
+ // From: emailer.Var1,
+ //}
+ //SendEmail(core.EmailBox, email)
+ return nil
+}
+
+// AFTER NOTIFIER LOADS, IF ENABLED, START A QUEUE PROCESS
+func (u *Email) Run() error {
+ 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 := u.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 u.Enabled {
+ return u.Run()
+ }
+ return nil
+}
+
+// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
+func (u *Email) OnFailure() error {
+ if u.Enabled {
+ 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 {
+ if u.Enabled {
+ utils.Log(1, fmt.Sprintf("Notification %v is receiving a failure notification.", u.Method))
+ // Do failing stuff 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
+}
+
+func (u *Email) 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 := u.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 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
new file mode 100644
index 00000000..07401e2f
--- /dev/null
+++ b/notifiers/notifiers.go
@@ -0,0 +1,173 @@
+package notifiers
+
+import (
+ "fmt"
+ "github.com/hunterlong/statup/utils"
+ "strings"
+ "time"
+ "upper.io/db.v3"
+)
+
+var (
+ AllCommunications []AllNotifiers
+ Collections db.Collection
+)
+
+type AllNotifiers interface{}
+
+func add(c interface{}) {
+ AllCommunications = append(AllCommunications, c)
+}
+
+func Load() []AllNotifiers {
+ utils.Log(1, "Loading notifiers")
+ var notifiers []AllNotifiers
+ for _, comm := range AllCommunications {
+ n := comm.(Notifier)
+ n.Init()
+ notifiers = append(notifiers, n)
+ n.Test()
+ }
+ return notifiers
+}
+
+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
+ Install() error
+ Run() error
+ OnFailure() error
+ OnSuccess() error
+ Select() *Notification
+ Test() error
+}
+
+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 SelectNotification(id int64) (*Notification, error) {
+ var notifier *Notification
+ err := Collections.Find("id", id).One(¬ifier)
+ return notifier, err
+}
+
+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 SelectNotifier(id int64) Notifier {
+ var notifier Notifier
+ for _, n := range AllCommunications {
+ notif := n.(Notifier)
+ n := notif.Select()
+ if n.Id == id {
+ return notif
+ }
+ }
+ 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 {
+ n := comm.(Notifier)
+ n.OnFailure()
+ }
+}
+
+func OnSuccess() {
+ for _, comm := range AllCommunications {
+ n := comm.(Notifier)
+ n.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..ed5648bd
--- /dev/null
+++ b/notifiers/slack.go
@@ -0,0 +1,137 @@
+package notifiers
+
+import (
+ "bytes"
+ "fmt"
+ "github.com/hunterlong/statup/utils"
+ "net/http"
+ "time"
+)
+
+const (
+ SLACK_ID = 2
+ SLACK_METHOD = "slack"
+)
+
+var (
+ slacker *Slack
+ slackMessages []string
+)
+
+type Slack struct {
+ *Notification
+}
+
+// DEFINE YOUR NOTIFICATION HERE.
+func init() {
+ 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 *Slack) Init() error {
+
+ err := u.Install()
+
+ if err == nil {
+ notifier, _ := SelectNotification(u.Id)
+ forms := u.Form
+ u.Notification = notifier
+ u.Form = forms
+ if u.Enabled {
+ go u.Run()
+ }
+ }
+
+ return err
+}
+
+func (u *Slack) Test() error {
+ SendSlack("Slack notifications on your Statup server is working!")
+ return nil
+}
+
+// AFTER NOTIFIER LOADS, IF ENABLED, START A QUEUE PROCESS
+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}
+ _, 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 *Slack) OnFailure() error {
+ if u.Enabled {
+ 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 *Slack) OnSuccess() error {
+ if u.Enabled {
+ 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 *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/source/tmpl/settings.html b/source/tmpl/settings.html
index 926eea21..26b2a705 100644
--- a/source/tmpl/settings.html
+++ b/source/tmpl/settings.html
@@ -32,11 +32,9 @@
- {{ with $c := index .Communications 0 }}
-