mirror of https://github.com/statping/statping
commit
b346740c6e
|
@ -18,7 +18,7 @@ services:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- VERSION=0.29.8
|
- VERSION=0.29.9
|
||||||
- DB_HOST=localhost
|
- DB_HOST=localhost
|
||||||
- DB_USER=travis
|
- DB_USER=travis
|
||||||
- DB_PASS=
|
- DB_PASS=
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
|
|
||||||
ENV VERSION=v0.29.8
|
ENV VERSION=v0.29.9
|
||||||
|
|
||||||
RUN apk --no-cache add libstdc++ ca-certificates
|
RUN apk --no-cache add libstdc++ ca-certificates
|
||||||
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \
|
RUN wget -q https://github.com/hunterlong/statup/releases/download/$VERSION/statup-linux-alpine.tar.gz && \
|
||||||
|
|
13
cli.go
13
cli.go
|
@ -5,7 +5,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hunterlong/statup/core"
|
"github.com/hunterlong/statup/core"
|
||||||
"github.com/hunterlong/statup/plugin"
|
"github.com/hunterlong/statup/plugin"
|
||||||
"github.com/hunterlong/statup/types"
|
|
||||||
"github.com/hunterlong/statup/utils"
|
"github.com/hunterlong/statup/utils"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -246,18 +245,6 @@ func FakeSeed(plug plugin.PluginActions) {
|
||||||
}
|
}
|
||||||
fakeUser.Create()
|
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++ {
|
for i := 0; i <= 50; i++ {
|
||||||
dd := core.HitData{
|
dd := core.HitData{
|
||||||
Latency: rand.Float64(),
|
Latency: rand.Float64(),
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -2,14 +2,19 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/go-yaml/yaml"
|
"github.com/go-yaml/yaml"
|
||||||
"github.com/hunterlong/statup/types"
|
"github.com/hunterlong/statup/types"
|
||||||
|
"github.com/hunterlong/statup/utils"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadConfig() (*types.Config, error) {
|
func LoadConfig() (*types.Config, error) {
|
||||||
if os.Getenv("DB_CONN") != "" {
|
if os.Getenv("DB_CONN") != "" {
|
||||||
|
utils.Log(1, "DB_CONN environment variable was found")
|
||||||
|
//time.Sleep(20 * time.Second)
|
||||||
return LoadUsingEnv()
|
return LoadUsingEnv()
|
||||||
}
|
}
|
||||||
Configs = new(types.Config)
|
Configs = new(types.Config)
|
||||||
|
@ -51,12 +56,65 @@ func LoadUsingEnv() (*types.Config, error) {
|
||||||
if os.Getenv("USE_CDN") == "true" {
|
if os.Getenv("USE_CDN") == "true" {
|
||||||
CoreApp.UseCdn = true
|
CoreApp.UseCdn = true
|
||||||
}
|
}
|
||||||
return Configs, nil
|
|
||||||
|
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",
|
||||||
}
|
}
|
||||||
|
|
||||||
func ifOr(val, def string) string {
|
err := DbConnection(dbConfig.DbConn)
|
||||||
if val == "" {
|
if err != nil {
|
||||||
return def
|
utils.Log(4, err)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return val
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
19
core/core.go
19
core/core.go
|
@ -2,6 +2,7 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/GeertJohan/go.rice"
|
"github.com/GeertJohan/go.rice"
|
||||||
|
"github.com/hunterlong/statup/notifiers"
|
||||||
"github.com/hunterlong/statup/plugin"
|
"github.com/hunterlong/statup/plugin"
|
||||||
"github.com/hunterlong/statup/types"
|
"github.com/hunterlong/statup/types"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -28,7 +29,7 @@ type Core struct {
|
||||||
Plugins []plugin.Info
|
Plugins []plugin.Info
|
||||||
Repos []PluginJSON
|
Repos []PluginJSON
|
||||||
AllPlugins []plugin.PluginActions
|
AllPlugins []plugin.PluginActions
|
||||||
Communications []*types.Communication
|
Communications []notifiers.AllNotifiers
|
||||||
DbConnection string
|
DbConnection string
|
||||||
started time.Time
|
started time.Time
|
||||||
}
|
}
|
||||||
|
@ -57,13 +58,18 @@ func NewCore() *Core {
|
||||||
return CoreApp
|
return CoreApp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Core) Insert() error {
|
||||||
|
col := DbSession.Collection("core")
|
||||||
|
_, err := col.Insert(c)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func InitApp() {
|
func InitApp() {
|
||||||
SelectCore()
|
SelectCore()
|
||||||
SelectAllCommunications()
|
notifiers.Collections = DbSession.Collection("communication")
|
||||||
InsertDefaultComms()
|
|
||||||
LoadDefaultCommunications()
|
|
||||||
SelectAllServices()
|
SelectAllServices()
|
||||||
CheckServices()
|
CheckServices()
|
||||||
|
CoreApp.Communications = notifiers.Load()
|
||||||
go DatabaseMaintence()
|
go DatabaseMaintence()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +127,11 @@ func SelectLastMigration() (int64, error) {
|
||||||
|
|
||||||
func SelectCore() (*Core, error) {
|
func SelectCore() (*Core, error) {
|
||||||
var c *Core
|
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)
|
err := DbSession.Collection("core").Find().One(&c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -135,6 +135,9 @@ func (c *DbConfig) Save() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreApp, err = SelectCore()
|
CoreApp, err = SelectCore()
|
||||||
|
if err != nil {
|
||||||
|
utils.Log(4, err)
|
||||||
|
}
|
||||||
CoreApp.DbConnection = c.DbConn
|
CoreApp.DbConnection = c.DbConn
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
@ -207,7 +210,7 @@ func RunDatabaseUpgrades() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func DropDatabase() {
|
func DropDatabase() {
|
||||||
fmt.Println("Dropping Tables...")
|
utils.Log(1, "Dropping Database Tables...")
|
||||||
down, _ := SqlBox.String("down.sql")
|
down, _ := SqlBox.String("down.sql")
|
||||||
requests := strings.Split(down, ";")
|
requests := strings.Split(down, ";")
|
||||||
for _, request := range requests {
|
for _, request := range requests {
|
||||||
|
@ -219,7 +222,7 @@ func DropDatabase() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateDatabase() {
|
func CreateDatabase() {
|
||||||
fmt.Println("Creating Tables...")
|
utils.Log(1, "Creating Database Tables...")
|
||||||
sql := "postgres_up.sql"
|
sql := "postgres_up.sql"
|
||||||
if CoreApp.DbConnection == "mysql" {
|
if CoreApp.DbConnection == "mysql" {
|
||||||
sql = "mysql_up.sql"
|
sql = "mysql_up.sql"
|
||||||
|
@ -236,7 +239,7 @@ func CreateDatabase() {
|
||||||
}
|
}
|
||||||
//secret := NewSHA1Hash()
|
//secret := NewSHA1Hash()
|
||||||
//db.QueryRow("INSERT INTO core (secret, version) VALUES ($1, $2);", secret, VERSION).Scan()
|
//db.QueryRow("INSERT INTO core (secret, version) VALUES ($1, $2);", secret, VERSION).Scan()
|
||||||
fmt.Println("Database Created")
|
utils.Log(1, "Database Created")
|
||||||
//SampleData()
|
//SampleData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/fatih/structs"
|
"github.com/fatih/structs"
|
||||||
"github.com/hunterlong/statup/notifications"
|
"github.com/hunterlong/statup/notifiers"
|
||||||
"github.com/hunterlong/statup/plugin"
|
"github.com/hunterlong/statup/plugin"
|
||||||
"github.com/hunterlong/statup/types"
|
|
||||||
"upper.io/db.v3/lib/sqlbuilder"
|
"upper.io/db.v3/lib/sqlbuilder"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,48 +17,14 @@ func OnSuccess(s *Service) {
|
||||||
for _, p := range CoreApp.AllPlugins {
|
for _, p := range CoreApp.AllPlugins {
|
||||||
p.OnSuccess(structs.Map(s))
|
p.OnSuccess(structs.Map(s))
|
||||||
}
|
}
|
||||||
|
notifiers.OnSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnFailure(s *Service, f FailureData) {
|
func OnFailure(s *Service, f FailureData) {
|
||||||
for _, p := range CoreApp.AllPlugins {
|
for _, p := range CoreApp.AllPlugins {
|
||||||
p.OnFailure(structs.Map(s))
|
p.OnFailure(structs.Map(s))
|
||||||
}
|
}
|
||||||
if notifications.SlackComm != nil {
|
notifiers.OnFailure()
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnSettingsSaved(c *Core) {
|
func OnSettingsSaved(c *Core) {
|
||||||
|
|
|
@ -58,6 +58,7 @@ func SelectAllServices() ([]*Service, error) {
|
||||||
err := col.All(&srvcs)
|
err := col.All(&srvcs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Log(3, err)
|
utils.Log(3, err)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, s := range srvcs {
|
for _, s := range srvcs {
|
||||||
s.Checkins = s.SelectAllCheckins()
|
s.Checkins = s.SelectAllCheckins()
|
||||||
|
|
|
@ -2,32 +2,10 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hunterlong/statup/types"
|
|
||||||
"github.com/hunterlong/statup/utils"
|
"github.com/hunterlong/statup/utils"
|
||||||
"os"
|
"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() {
|
func DeleteConfig() {
|
||||||
err := os.Remove("./config.yml")
|
err := os.Remove("./config.yml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -95,15 +73,15 @@ func LoadSampleData() error {
|
||||||
utils.Log(3, fmt.Sprintf("Error creating Service %v: %v", id, err))
|
utils.Log(3, fmt.Sprintf("Error creating Service %v: %v", id, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
checkin := &Checkin{
|
//checkin := &Checkin{
|
||||||
Service: s2.Id,
|
// Service: s2.Id,
|
||||||
Interval: 30,
|
// Interval: 30,
|
||||||
Api: utils.NewSHA1Hash(18),
|
// Api: utils.NewSHA1Hash(18),
|
||||||
}
|
//}
|
||||||
id, err = checkin.Create()
|
//id, err = checkin.Create()
|
||||||
if err != nil {
|
//if err != nil {
|
||||||
utils.Log(3, fmt.Sprintf("Error creating Checkin %v: %v", id, err))
|
// utils.Log(3, fmt.Sprintf("Error creating Checkin %v: %v", id, err))
|
||||||
}
|
//}
|
||||||
|
|
||||||
//for i := 0; i < 3; i++ {
|
//for i := 0; i < 3; i++ {
|
||||||
// s1.Check()
|
// s1.Check()
|
||||||
|
|
|
@ -37,8 +37,7 @@ func Router() *mux.Router {
|
||||||
r.Handle("/settings", http.HandlerFunc(SaveSettingsHandler)).Methods("POST")
|
r.Handle("/settings", http.HandlerFunc(SaveSettingsHandler)).Methods("POST")
|
||||||
r.Handle("/settings/css", http.HandlerFunc(SaveSASSHandler)).Methods("POST")
|
r.Handle("/settings/css", http.HandlerFunc(SaveSASSHandler)).Methods("POST")
|
||||||
r.Handle("/settings/build", http.HandlerFunc(SaveAssetsHandler)).Methods("GET")
|
r.Handle("/settings/build", http.HandlerFunc(SaveAssetsHandler)).Methods("GET")
|
||||||
r.Handle("/settings/email", http.HandlerFunc(SaveEmailSettingsHandler)).Methods("POST")
|
r.Handle("/settings/notifier/{id}", http.HandlerFunc(SaveNotificationHandler)).Methods("POST")
|
||||||
r.Handle("/settings/slack", http.HandlerFunc(SaveSlackSettingsHandler)).Methods("POST")
|
|
||||||
r.Handle("/plugins/download/{name}", http.HandlerFunc(PluginsDownloadHandler))
|
r.Handle("/plugins/download/{name}", http.HandlerFunc(PluginsDownloadHandler))
|
||||||
r.Handle("/plugins/{name}/save", http.HandlerFunc(PluginSavedHandler)).Methods("POST")
|
r.Handle("/plugins/{name}/save", http.HandlerFunc(PluginSavedHandler)).Methods("POST")
|
||||||
r.Handle("/help", http.HandlerFunc(HelpHandler))
|
r.Handle("/help", http.HandlerFunc(HelpHandler))
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
"github.com/hunterlong/statup/core"
|
"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"
|
"github.com/hunterlong/statup/utils"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
@ -84,65 +85,72 @@ func SaveAssetsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "/settings", http.StatusSeeOther)
|
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) {
|
if !IsAuthenticated(r) {
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
emailer := core.SelectCommunication(1)
|
vars := mux.Vars(r)
|
||||||
r.ParseForm()
|
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
|
notifierId := vars["id"]
|
||||||
emailer.Username = smtpUser
|
enabled := r.PostForm.Get("enable")
|
||||||
if smtpPass != "#######################" {
|
|
||||||
emailer.Password = smtpPass
|
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" {
|
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{
|
if notifer.Enabled {
|
||||||
To: SessionUser(r).Email,
|
notify := notifiers.SelectNotifier(notifer.Id)
|
||||||
Subject: "Test Email",
|
go notify.Run()
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils.Log(1, fmt.Sprintf("Notifier saved: %v", notifer))
|
||||||
|
|
||||||
http.Redirect(w, r, "/settings", http.StatusSeeOther)
|
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)
|
|
||||||
}
|
|
||||||
|
|
2
main.go
2
main.go
|
@ -65,7 +65,7 @@ func mainProcess() {
|
||||||
var err error
|
var err error
|
||||||
err = core.DbConnection(core.Configs.Connection)
|
err = core.DbConnection(core.Configs.Connection)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Log(3, err)
|
utils.Log(4, fmt.Sprintf("could not connect to database: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
core.RunDatabaseUpgrades()
|
core.RunDatabaseUpgrades()
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/hunterlong/statup/core"
|
"github.com/hunterlong/statup/core"
|
||||||
"github.com/hunterlong/statup/handlers"
|
"github.com/hunterlong/statup/handlers"
|
||||||
|
"github.com/hunterlong/statup/notifiers"
|
||||||
"github.com/rendon/testcli"
|
"github.com/rendon/testcli"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -218,7 +219,6 @@ func RunMySQLMakeConfig(t *testing.T, db string) {
|
||||||
|
|
||||||
err = core.DbConnection(core.Configs.Connection)
|
err = core.DbConnection(core.Configs.Connection)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
core.InsertDefaultComms()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunInsertMysqlSample(t *testing.T) {
|
func RunInsertMysqlSample(t *testing.T) {
|
||||||
|
@ -254,7 +254,8 @@ func RunSelectAllMysqlServices(t *testing.T) {
|
||||||
|
|
||||||
func RunSelectAllMysqlCommunications(t *testing.T) {
|
func RunSelectAllMysqlCommunications(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
comms, err := core.SelectAllCommunications()
|
notifiers.Collections = core.DbSession.Collection("communication")
|
||||||
|
comms := notifiers.Load()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, 2, len(comms))
|
assert.Equal(t, 2, len(comms))
|
||||||
}
|
}
|
||||||
|
@ -533,7 +534,6 @@ func RunSettingsHandler(t *testing.T) {
|
||||||
route.ServeHTTP(rr, req)
|
route.ServeHTTP(rr, req)
|
||||||
assert.True(t, strings.Contains(rr.Body.String(), "<title>Statup | Settings</title>"))
|
assert.True(t, strings.Contains(rr.Body.String(), "<title>Statup | Settings</title>"))
|
||||||
assert.True(t, strings.Contains(rr.Body.String(), "Theme Editor"))
|
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"))
|
assert.True(t, strings.Contains(rr.Body.String(), "footer"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -32,10 +32,8 @@
|
||||||
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||||
<a class="nav-link active" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true">Settings</a>
|
<a class="nav-link active" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true">Settings</a>
|
||||||
<a class="nav-link" id="v-pills-style-tab" data-toggle="pill" href="#v-pills-style" role="tab" aria-controls="v-pills-style" aria-selected="false">Theme Editor</a>
|
<a class="nav-link" id="v-pills-style-tab" data-toggle="pill" href="#v-pills-style" role="tab" aria-controls="v-pills-style" aria-selected="false">Theme Editor</a>
|
||||||
<a class="nav-link" id="v-pills-email-tab" data-toggle="pill" href="#v-pills-email" role="tab" aria-controls="v-pills-email" aria-selected="true">Email Settings</a>
|
|
||||||
<a class="nav-link" id="v-pills-slack-tab" data-toggle="pill" href="#v-pills-slack" role="tab" aria-controls="v-pills-slack" aria-selected="true">Slack Updates</a>
|
|
||||||
{{ range .Communications }}
|
{{ range .Communications }}
|
||||||
|
<a class="nav-link text-capitalize" id="v-pills-{{underscore .Method}}-tab" data-toggle="pill" href="#v-pills-{{underscore .Method}}" role="tab" aria-controls="v-pills-{{underscore .Method}}" aria-selected="false">{{.Method}}</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<a class="nav-link" id="v-pills-browse-tab" data-toggle="pill" href="#v-pills-browse" role="tab" aria-controls="v-pills-home" aria-selected="false">Browse Plugins</a>
|
<a class="nav-link" id="v-pills-browse-tab" data-toggle="pill" href="#v-pills-browse" role="tab" aria-controls="v-pills-home" aria-selected="false">Browse Plugins</a>
|
||||||
{{ range .Plugins }}
|
{{ range .Plugins }}
|
||||||
|
@ -122,87 +120,29 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{ with $c := index .Communications 0 }}
|
|
||||||
<div class="tab-pane fade" id="v-pills-{{ $c.Method }}" role="tabpanel" aria-labelledby="v-pills-{{ $c.Method }}-tab">
|
|
||||||
|
|
||||||
<form method="POST" action="/settings/{{ $c.Method }}">
|
|
||||||
|
|
||||||
|
{{ range .Communications }}
|
||||||
|
<div class="tab-pane fade" id="v-pills-{{underscore .Method}}" role="tabpanel" aria-labelledby="v-pills-{{underscore .Method }}-tab">
|
||||||
|
<form method="POST" action="/settings/notifier/{{ .Id }}">
|
||||||
|
{{range .Form}}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="host">SMTP Host</label>
|
<label class="text-capitalize" for="{{underscore .Title}}">{{.Title}}</label>
|
||||||
<input type="text" name="host" class="form-control" value="{{ $c.Host }}" id="host" placeholder="Great Uptime">
|
<input type="{{.Type}}" name="{{underscore .DbField}}" class="form-control" value="{{ .Value }}" id="{{underscore .Title}}" placeholder="{{.Placeholder}}">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="username">SMTP Username</label>
|
|
||||||
<input type="text" name="username" class="form-control" value="{{ $c.Username }}" id="username" placeholder="Great Uptime">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="password">SMTP Password</label>
|
|
||||||
<input type="password" name="password" class="form-control" value="{{ if $c.Password }}#######################{{end}}" id="password">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="port">SMTP Port</label>
|
|
||||||
<input type="number" name="port" class="form-control" value="{{ $c.Port }}" id="port" placeholder="587">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="address">Outgoing Email Address</label>
|
|
||||||
<input type="text" name="address" class="form-control" value="{{ $c.Var1 }}" id="address" placeholder="noreply@domain.com">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="limit">Limit Emails per Hour</label>
|
|
||||||
<input type="number" name="limit" class="form-control" value="30" id="limit" placeholder="noreply@domain.com">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<span class="switch">
|
|
||||||
<input type="checkbox" name="enable_{{ $c.Method }}" class="switch" id="switch-{{ $c.Method }}" {{if .Enabled}}checked{{end}}>
|
|
||||||
<label for="switch-{{ $c.Method }}">Enable Emails</label>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<button type="submit" class="btn btn-primary btn-block">Save Email Settings</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|
||||||
{{ with $c := index .Communications 1 }}
|
|
||||||
<div class="tab-pane fade" id="v-pills-{{ $c.Method }}" role="tabpanel" aria-labelledby="v-pills-{{ $c.Method }}-tab">
|
|
||||||
|
|
||||||
<form method="POST" action="/settings/{{ $c.Method }}">
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="slack_url">Slack Webhook URL</label>
|
|
||||||
<input type="text" name="slack_url" class="form-control" value="{{ $c.Host }}" id="slack_url" placeholder="https://hooks.slack.com/services/TJIIDSJIFJ/729FJSDF/hua463asda9af79">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<span class="switch">
|
<span class="switch">
|
||||||
<input type="checkbox" name="enable_{{ $c.Method }}" class="switch" id="switch-{{ $c.Method }}" {{if .Enabled}}checked{{end}}>
|
<input type="checkbox" name="enable" class="switch" id="switch-{{ .Method }}" {{if .Enabled}}checked{{end}}>
|
||||||
<label for="switch-{{ $c.Method }}">Enable Slack</label>
|
<label for="switch-{{ .Method }}">Enable {{ .Method }}</label>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<button type="submit" class="btn btn-primary btn-block">Save Slack Settings</button>
|
<button type="submit" class="btn btn-primary btn-block text-capitalize">Save {{ .Method }} Settings</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
|
|
@ -40,24 +40,6 @@ type Checkin struct {
|
||||||
Last time.Time `json:"last"`
|
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 {
|
type Email struct {
|
||||||
To string
|
To string
|
||||||
Subject string
|
Subject string
|
||||||
|
|
Loading…
Reference in New Issue