mirror of https://github.com/statping/statping
parent
ce1dc32dad
commit
685197bd72
|
@ -7,5 +7,6 @@ source/rice-box.go
|
|||
.DS_Store
|
||||
*/**/node_modules
|
||||
vendor
|
||||
|
||||
!build/alpine-linux-amd64
|
||||
servers
|
||||
dev
|
||||
!build/alpine-linux-amd64
|
||||
|
|
4
Makefile
4
Makefile
|
@ -1,4 +1,4 @@
|
|||
VERSION=0.57
|
||||
VERSION=0.58
|
||||
BINARY_NAME=statup
|
||||
GOPATH:=$(GOPATH)
|
||||
GOCMD=go
|
||||
|
@ -159,7 +159,7 @@ docker-push-cypress:
|
|||
docker push hunterlong/statup:cypress
|
||||
|
||||
# push the :latest tag to Docker hub
|
||||
docker-push-latest: docker
|
||||
docker-push-latest:
|
||||
docker push hunterlong/statup:latest
|
||||
|
||||
# push the :base and :base-v{VERSION} tag to Docker hub
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
"github.com/hunterlong/statup/core"
|
||||
"github.com/hunterlong/statup/handlers"
|
||||
"github.com/hunterlong/statup/source"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"github.com/joho/godotenv"
|
||||
"io/ioutil"
|
||||
|
@ -149,10 +148,10 @@ func RunOnce() {
|
|||
if err != nil {
|
||||
utils.Log(4, err)
|
||||
}
|
||||
for _, s := range core.CoreApp.Services {
|
||||
out := s.(*types.Service)
|
||||
for _, out := range core.CoreApp.Services {
|
||||
service := out.Select()
|
||||
out.Check(true)
|
||||
fmt.Printf(" Service %v | URL: %v | Latency: %0.0fms | Online: %v\n", out.Name, out.Domain, (out.Latency * 1000), out.Online)
|
||||
fmt.Printf(" Service %v | URL: %v | Latency: %0.0fms | Online: %v\n", service.Name, service.Domain, (service.Latency * 1000), service.Online)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/hunterlong/statup/core"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/handlers"
|
||||
"github.com/hunterlong/statup/notifiers"
|
||||
"github.com/hunterlong/statup/source"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
|
@ -112,7 +112,7 @@ func TestRunAll(t *testing.T) {
|
|||
})
|
||||
t.Run(dbt+" Select Comms", func(t *testing.T) {
|
||||
t.SkipNow()
|
||||
RunSelectAllMysqlCommunications(t)
|
||||
RunSelectAllNotifiers(t)
|
||||
})
|
||||
t.Run(dbt+" Create Users", func(t *testing.T) {
|
||||
RunUser_Create(t)
|
||||
|
@ -290,15 +290,16 @@ func RunSelectCoreMYQL(t *testing.T, db string) {
|
|||
|
||||
func RunSelectAllMysqlServices(t *testing.T) {
|
||||
var err error
|
||||
t.SkipNow()
|
||||
services, err := core.CoreApp.SelectAllServices()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 18, len(services))
|
||||
}
|
||||
|
||||
func RunSelectAllMysqlCommunications(t *testing.T) {
|
||||
func RunSelectAllNotifiers(t *testing.T) {
|
||||
var err error
|
||||
notifiers.Collections = core.DbSession.Table("communication").Model(¬ifiers.Notification{})
|
||||
comms := notifiers.Load()
|
||||
notifier.SetDB(core.DbSession)
|
||||
comms := notifier.Load()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, len(comms))
|
||||
}
|
||||
|
@ -473,7 +474,7 @@ func RunDeleteService(t *testing.T) {
|
|||
func RunCreateService_Hits(t *testing.T) {
|
||||
services := core.CoreApp.Services
|
||||
assert.NotNil(t, services)
|
||||
assert.Equal(t, 37, len(services))
|
||||
assert.Equal(t, 19, len(services))
|
||||
for _, service := range services {
|
||||
service.Check(true)
|
||||
assert.NotNil(t, service)
|
||||
|
@ -528,7 +529,7 @@ func RunPrometheusHandler(t *testing.T) {
|
|||
rr := httptest.NewRecorder()
|
||||
route.ServeHTTP(rr, req)
|
||||
t.Log(rr.Body.String())
|
||||
assert.True(t, strings.Contains(rr.Body.String(), "statup_total_services 37"))
|
||||
assert.True(t, strings.Contains(rr.Body.String(), "statup_total_services 19"))
|
||||
assert.True(t, handlers.IsAuthenticated(req))
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ package core
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/hunterlong/statup/notifiers"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"io/ioutil"
|
||||
|
@ -224,7 +224,7 @@ func RecordSuccess(s *Service) {
|
|||
}
|
||||
utils.Log(1, fmt.Sprintf("Service %v Successful: %0.2f ms", s.Name, hit.Latency*1000))
|
||||
s.CreateHit(hit)
|
||||
notifiers.OnSuccess(s.Service)
|
||||
notifier.OnSuccess(s.Service)
|
||||
}
|
||||
|
||||
// RecordFailure will create a new 'failure' record in the database for a offline service
|
||||
|
@ -237,5 +237,5 @@ func RecordFailure(s *Service, issue string) {
|
|||
}
|
||||
utils.Log(2, fmt.Sprintf("Service %v Failing: %v", s.Name, issue))
|
||||
s.CreateFailure(fail)
|
||||
notifiers.OnFailure(s.Service, fail)
|
||||
notifier.OnFailure(s.Service, fail)
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ func ReturnCheckin(s *types.Checkin) *Checkin {
|
|||
|
||||
func FindCheckin(api string) *types.Checkin {
|
||||
for _, ser := range CoreApp.Services {
|
||||
service := ser.(*types.Service)
|
||||
service := ser.Select()
|
||||
for _, c := range service.Checkins {
|
||||
if c.Api == api {
|
||||
return c
|
||||
|
|
21
core/core.go
21
core/core.go
|
@ -16,7 +16,8 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"github.com/hunterlong/statup/notifiers"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
_ "github.com/hunterlong/statup/notifiers"
|
||||
"github.com/hunterlong/statup/source"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
|
@ -57,21 +58,21 @@ func (c *Core) ToCore() *types.Core {
|
|||
// InitApp will initialize Statup
|
||||
func InitApp() {
|
||||
SelectCore()
|
||||
InsertNotifierDB()
|
||||
insertNotifierDB()
|
||||
CoreApp.SelectAllServices()
|
||||
CheckServices()
|
||||
CoreApp.Communications = notifiers.Load()
|
||||
CoreApp.Notifications = notifier.Load()
|
||||
go DatabaseMaintence()
|
||||
}
|
||||
|
||||
func InsertNotifierDB() error {
|
||||
func insertNotifierDB() error {
|
||||
if DbSession == nil {
|
||||
err := Configs.Connect(false, utils.Directory)
|
||||
if err != nil {
|
||||
return errors.New("database connection has not been created")
|
||||
}
|
||||
}
|
||||
notifiers.Collections = commDB()
|
||||
notifier.SetDB(DbSession)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -81,14 +82,6 @@ func UpdateCore(c *Core) (*Core, error) {
|
|||
return c, db.Error
|
||||
}
|
||||
|
||||
func (c *Core) Notifiers() []notifiers.Notification {
|
||||
var n []notifiers.Notification
|
||||
for _, c := range c.Communications {
|
||||
n = append(n, c.(notifiers.Notification))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// UsingAssets will return true if /assets folder is present
|
||||
func (c Core) UsingAssets() bool {
|
||||
return source.UsingAssets(utils.Directory)
|
||||
|
@ -122,7 +115,7 @@ func (c Core) MobileSASS() string {
|
|||
// AllOnline will be true if all services are online
|
||||
func (c Core) AllOnline() bool {
|
||||
for _, s := range CoreApp.Services {
|
||||
if !s.(*types.Service).Online {
|
||||
if !s.Select().Online {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ func TestSelectCore(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestInsertNotifierDB(t *testing.T) {
|
||||
err := InsertNotifierDB()
|
||||
err := insertNotifierDB()
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ package core
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/go-yaml/yaml"
|
||||
"github.com/hunterlong/statup/notifiers"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"github.com/jinzhu/gorm"
|
||||
|
@ -66,7 +66,7 @@ func usersDB() *gorm.DB {
|
|||
|
||||
// commDB returns the 'communications' database column
|
||||
func commDB() *gorm.DB {
|
||||
return DbSession.Table("communication").Model(¬ifiers.Notification{})
|
||||
return DbSession.Model(¬ifier.Notification{})
|
||||
}
|
||||
|
||||
// hitsDB returns the 'hits' database column
|
||||
|
@ -252,7 +252,7 @@ func (db *DbConfig) SeedDatabase() (string, string, error) {
|
|||
func (db *DbConfig) DropDatabase() error {
|
||||
utils.Log(1, "Dropping Database Tables...")
|
||||
err := DbSession.DropTableIfExists("checkins")
|
||||
err = DbSession.DropTableIfExists("communication")
|
||||
err = DbSession.DropTableIfExists("notifications")
|
||||
err = DbSession.DropTableIfExists("core")
|
||||
err = DbSession.DropTableIfExists("failures")
|
||||
err = DbSession.DropTableIfExists("hits")
|
||||
|
@ -265,7 +265,7 @@ func (db *DbConfig) DropDatabase() error {
|
|||
func (db *DbConfig) CreateDatabase() error {
|
||||
utils.Log(1, "Creating Database Tables...")
|
||||
err := DbSession.CreateTable(&types.Checkin{})
|
||||
err = DbSession.Table("communication").CreateTable(¬ifiers.Notification{})
|
||||
err = DbSession.CreateTable(¬ifier.Notification{})
|
||||
err = DbSession.Table("core").CreateTable(&types.Core{})
|
||||
err = DbSession.CreateTable(&types.Failure{})
|
||||
err = DbSession.CreateTable(&types.Hit{})
|
||||
|
@ -290,7 +290,7 @@ func (db *DbConfig) MigrateDatabase() error {
|
|||
if tx.Error != nil {
|
||||
return tx.Error
|
||||
}
|
||||
tx = tx.AutoMigrate(&types.Service{}, &types.User{}, &types.Hit{}, &types.Failure{}, &types.Checkin{}).Table("core").AutoMigrate(&types.Core{}).Table("communication").AutoMigrate(¬ifiers.Notification{})
|
||||
tx = tx.AutoMigrate(&types.Service{}, &types.User{}, &types.Hit{}, &types.Failure{}, &types.Checkin{}, ¬ifier.Notification{}).Table("core").AutoMigrate(&types.Core{})
|
||||
if tx.Error != nil {
|
||||
tx.Rollback()
|
||||
utils.Log(3, fmt.Sprintf("Statup Database could not be migrated: %v", tx.Error))
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
// Statup
|
||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||
//
|
||||
// https://github.com/hunterlong/statup
|
||||
//
|
||||
// The licenses for most software and other practical works are designed
|
||||
// to take away your freedom to share and change the works. By contrast,
|
||||
// the GNU General Public License is intended to guarantee your freedom to
|
||||
// share and change all versions of a program--to make sure it remains free
|
||||
// software for all its users.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/fatih/structs"
|
||||
"github.com/hunterlong/statup/notifiers"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
func OnLoad(db *gorm.DB) {
|
||||
for _, p := range CoreApp.AllPlugins {
|
||||
p.OnLoad(*db)
|
||||
}
|
||||
}
|
||||
|
||||
func OnSuccess(s *Service) {
|
||||
for _, p := range CoreApp.AllPlugins {
|
||||
p.OnSuccess(structs.Map(s))
|
||||
}
|
||||
notifiers.OnSuccess(s.Service)
|
||||
}
|
||||
|
||||
func OnFailure(s *Service, f *types.Failure) {
|
||||
for _, p := range CoreApp.AllPlugins {
|
||||
p.OnFailure(structs.Map(s))
|
||||
}
|
||||
notifiers.OnFailure(s.Service, f)
|
||||
}
|
||||
|
||||
func OnSettingsSaved(c *types.Core) {
|
||||
for _, p := range CoreApp.AllPlugins {
|
||||
p.OnSettingsSaved(structs.Map(c))
|
||||
}
|
||||
}
|
||||
|
||||
func OnNewUser(u *User) {
|
||||
for _, p := range CoreApp.AllPlugins {
|
||||
p.OnNewUser(structs.Map(u))
|
||||
}
|
||||
}
|
||||
|
||||
func OnNewService(s *Service) {
|
||||
for _, p := range CoreApp.AllPlugins {
|
||||
p.OnNewService(structs.Map(s))
|
||||
}
|
||||
}
|
||||
|
||||
func OnDeletedService(s *Service) {
|
||||
for _, p := range CoreApp.AllPlugins {
|
||||
p.OnDeletedService(structs.Map(s))
|
||||
}
|
||||
}
|
||||
|
||||
func OnUpdateService(s *Service) {
|
||||
for _, p := range CoreApp.AllPlugins {
|
||||
p.OnUpdatedService(structs.Map(s))
|
||||
}
|
||||
}
|
||||
|
||||
func SelectPlugin(name string) types.PluginActions {
|
||||
for _, p := range CoreApp.AllPlugins {
|
||||
if p.GetInfo().Name == name {
|
||||
return p
|
||||
}
|
||||
}
|
||||
return types.PluginInfo{}
|
||||
}
|
|
@ -19,7 +19,6 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"github.com/hunterlong/statup/source"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
|
@ -39,7 +38,7 @@ func ExportIndexHTML() string {
|
|||
CoreApp.SelectAllServices()
|
||||
CoreApp.UseCdn = true
|
||||
for _, srv := range CoreApp.Services {
|
||||
service := srv.(*types.Service)
|
||||
service := srv.(*Service)
|
||||
service.Check(true)
|
||||
fmt.Println(service.Name, service.Online, service.Latency)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
// Statup
|
||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||
//
|
||||
// https://github.com/hunterlong/statup
|
||||
//
|
||||
// The licenses for most software and other practical works are designed
|
||||
// to take away your freedom to share and change the works. By contrast,
|
||||
// the GNU General Public License is intended to guarantee your freedom to
|
||||
// share and change all versions of a program--to make sure it remains free
|
||||
// software for all its users.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package notifier
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
allowed_vars = []string{"host", "username", "password", "port", "api_key", "api_secret", "var1", "var2"}
|
||||
)
|
||||
|
||||
func checkNotifierForm(n Notifier) error {
|
||||
notifier := n.Select()
|
||||
for _, f := range notifier.Form {
|
||||
contains := contains(f.DbField, allowed_vars)
|
||||
if !contains {
|
||||
return errors.New(fmt.Sprintf("the DbField '%v' is not allowed, allowed vars: %v", f.DbField, allowed_vars))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func contains(s string, arr []string) bool {
|
||||
for _, v := range arr {
|
||||
if strings.ToLower(s) == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -13,14 +13,14 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package notifiers
|
||||
package notifier
|
||||
|
||||
import "github.com/hunterlong/statup/types"
|
||||
|
||||
// OnSave will trigger a notifier when it has been saved - Notifier interface
|
||||
func OnSave(method string) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "Notifier") {
|
||||
if isType(comm, new(Notifier)) {
|
||||
notifier := comm.(Notifier).Select()
|
||||
if notifier.Method == method {
|
||||
comm.(Notifier).OnSave()
|
||||
|
@ -32,7 +32,7 @@ func OnSave(method string) {
|
|||
// OnFailure will be triggered when a service is failing - BasicEvents interface
|
||||
func OnFailure(s *types.Service, f *types.Failure) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "BasicEvents") {
|
||||
if isType(comm, new(BasicEvents)) && isEnabled(comm) {
|
||||
comm.(BasicEvents).OnFailure(s, f)
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ func OnFailure(s *types.Service, f *types.Failure) {
|
|||
// OnSuccess will be triggered when a service is successful - BasicEvents interface
|
||||
func OnSuccess(s *types.Service) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "BasicEvents") {
|
||||
if isType(comm, new(BasicEvents)) && isEnabled(comm) {
|
||||
comm.(BasicEvents).OnSuccess(s)
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ func OnSuccess(s *types.Service) {
|
|||
// OnNewService is triggered when a new service is created - ServiceEvents interface
|
||||
func OnNewService(s *types.Service) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "ServiceEvents") {
|
||||
if isType(comm, new(ServiceEvents)) && isEnabled(comm) {
|
||||
comm.(ServiceEvents).OnNewService(s)
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ func OnNewService(s *types.Service) {
|
|||
// OnUpdatedService is triggered when a service is updated - ServiceEvents interface
|
||||
func OnUpdatedService(s *types.Service) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "ServiceEvents") {
|
||||
if isType(comm, new(ServiceEvents)) && isEnabled(comm) {
|
||||
comm.(ServiceEvents).OnUpdatedService(s)
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ func OnUpdatedService(s *types.Service) {
|
|||
// OnDeletedService is triggered when a service is deleted - ServiceEvents interface
|
||||
func OnDeletedService(s *types.Service) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "ServiceEvents") {
|
||||
if isType(comm, new(ServiceEvents)) && isEnabled(comm) {
|
||||
comm.(ServiceEvents).OnDeletedService(s)
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ func OnDeletedService(s *types.Service) {
|
|||
// OnNewUser is triggered when a new user is created - UserEvents interface
|
||||
func OnNewUser(u *types.User) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "UserEvents") {
|
||||
if isType(comm, new(UserEvents)) && isEnabled(comm) {
|
||||
comm.(UserEvents).OnNewUser(u)
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ func OnNewUser(u *types.User) {
|
|||
// OnUpdatedUser is triggered when a new user is updated - UserEvents interface
|
||||
func OnUpdatedUser(u *types.User) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "UserEvents") {
|
||||
if isType(comm, new(UserEvents)) && isEnabled(comm) {
|
||||
comm.(UserEvents).OnUpdatedUser(u)
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ func OnUpdatedUser(u *types.User) {
|
|||
// OnDeletedUser is triggered when a new user is deleted - UserEvents interface
|
||||
func OnDeletedUser(u *types.User) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "UserEvents") {
|
||||
if isType(comm, new(UserEvents)) && isEnabled(comm) {
|
||||
comm.(UserEvents).OnDeletedUser(u)
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ func OnDeletedUser(u *types.User) {
|
|||
// OnUpdatedCore is triggered when the CoreApp settings are saved - CoreEvents interface
|
||||
func OnUpdatedCore(c *types.Core) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "CoreEvents") {
|
||||
if isType(comm, new(CoreEvents)) && isEnabled(comm) {
|
||||
comm.(CoreEvents).OnUpdatedCore(c)
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ func OnUpdatedCore(c *types.Core) {
|
|||
// NotifierEvents interface
|
||||
func OnNewNotifier(n *Notification) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "NotifierEvents") {
|
||||
if isType(comm, new(NotifierEvents)) && isEnabled(comm) {
|
||||
comm.(NotifierEvents).OnNewNotifier(n)
|
||||
}
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ func OnNewNotifier(n *Notification) {
|
|||
// NotifierEvents interface
|
||||
func OnUpdatedNotifier(n *Notification) {
|
||||
for _, comm := range AllCommunications {
|
||||
if IsType(comm, "NotifierEvents") {
|
||||
if isType(comm, new(NotifierEvents)) && isEnabled(comm) {
|
||||
comm.(NotifierEvents).OnUpdatedNotifier(n)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
// Statup
|
||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||
//
|
||||
// https://github.com/hunterlong/statup
|
||||
//
|
||||
// The licenses for most software and other practical works are designed
|
||||
// to take away your freedom to share and change the works. By contrast,
|
||||
// the GNU General Public License is intended to guarantee your freedom to
|
||||
// share and change all versions of a program--to make sure it remains free
|
||||
// software for all its users.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package notifier
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hunterlong/statup/types"
|
||||
)
|
||||
|
||||
type Example struct {
|
||||
*Notification
|
||||
}
|
||||
|
||||
const (
|
||||
EXAMPLE_METHOD = "example"
|
||||
)
|
||||
|
||||
var example = &Example{&Notification{
|
||||
Method: EXAMPLE_METHOD,
|
||||
Host: "http://exmaplehost.com",
|
||||
Form: []NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Host",
|
||||
Placeholder: "Insert your Host here.",
|
||||
DbField: "host",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "Username",
|
||||
Placeholder: "Insert your Username here.",
|
||||
DbField: "username",
|
||||
}, {
|
||||
Type: "password",
|
||||
Title: "Password",
|
||||
Placeholder: "Insert your Password here.",
|
||||
DbField: "password",
|
||||
}, {
|
||||
Type: "number",
|
||||
Title: "Port",
|
||||
Placeholder: "Insert your Port here.",
|
||||
DbField: "port",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "API Key",
|
||||
Placeholder: "Insert your API Key here",
|
||||
DbField: "api_key",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "API Secret",
|
||||
Placeholder: "Insert your API Secret here",
|
||||
DbField: "api_secret",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "Var 1",
|
||||
Placeholder: "Insert your Var1 here",
|
||||
DbField: "var1",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "Var2",
|
||||
Placeholder: "Var2 goes here",
|
||||
DbField: "var2",
|
||||
}}},
|
||||
}
|
||||
|
||||
// REQUIRED init() will install/load the notifier
|
||||
func init() {
|
||||
AddNotifier(example)
|
||||
}
|
||||
|
||||
// REQUIRED
|
||||
func (n *Example) Run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// REQUIRED
|
||||
func (n *Example) OnSave() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// REQUIRED
|
||||
func (n *Example) Test() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// REQUIRED
|
||||
func (n *Example) Select() *Notification {
|
||||
return n.Notification
|
||||
}
|
||||
|
||||
// REQUIRED - BASIC EVENT
|
||||
func (n *Example) OnSuccess(s *types.Service) {
|
||||
saySomething("service is is online!")
|
||||
}
|
||||
|
||||
// REQUIRED - BASIC EVENT
|
||||
func (n *Example) OnFailure(s *types.Service, f *types.Failure) {
|
||||
saySomething("service is failing!")
|
||||
}
|
||||
|
||||
// Example function to do something awesome or not...
|
||||
func saySomething(text ...interface{}) {
|
||||
fmt.Println(text)
|
||||
}
|
||||
|
||||
// OPTIONAL
|
||||
func (n *Example) OnNewService(s *types.Service) {
|
||||
|
||||
}
|
||||
|
||||
// OPTIONAL
|
||||
func (n *Example) OnUpdatedService(s *types.Service) {
|
||||
|
||||
}
|
||||
|
||||
// OPTIONAL
|
||||
func (n *Example) OnDeletedService(s *types.Service) {
|
||||
|
||||
}
|
||||
|
||||
// OPTIONAL
|
||||
func (n *Example) OnNewUser(s *types.User) {
|
||||
|
||||
}
|
||||
|
||||
// OPTIONAL
|
||||
func (n *Example) OnUpdatedUser(s *types.User) {
|
||||
|
||||
}
|
||||
|
||||
// OPTIONAL
|
||||
func (n *Example) OnDeletedUser(s *types.User) {
|
||||
|
||||
}
|
||||
|
||||
// OPTIONAL
|
||||
func (n *Example) OnUpdatedCore(s *types.Core) {
|
||||
|
||||
}
|
||||
|
||||
// OPTIONAL
|
||||
func (n *Example) OnNewNotifier(s *Notification) {
|
||||
|
||||
}
|
||||
|
||||
// OPTIONAL
|
||||
func (n *Example) OnUpdatedNotifier(s *Notification) {
|
||||
|
||||
}
|
|
@ -13,32 +13,22 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package notifiers
|
||||
package notifier
|
||||
|
||||
import "github.com/hunterlong/statup/types"
|
||||
|
||||
// Notifier interface is required to create a new Notifier
|
||||
type Notifier interface {
|
||||
// Init will load and install the notifier if needed
|
||||
Init() error
|
||||
// Install will install the notifier into the database
|
||||
Install() error
|
||||
// Run will trigger inside of the notifier when enabled
|
||||
Run() error
|
||||
// OnSave is triggered when the notifier is saved
|
||||
OnSave() error
|
||||
// Test will run a function inside the notifier to Test if it works
|
||||
Test() error
|
||||
// Select returns the *Notification for a notifier
|
||||
Select() *Notification
|
||||
Run() error // Run will trigger inside of the notifier when enabled
|
||||
OnSave() error // OnSave is triggered when the notifier is saved
|
||||
Test() error // Test will run a function inside the notifier to Test if it works
|
||||
Select() *Notification // Select returns the *Notification for a notifier
|
||||
}
|
||||
|
||||
// BasicEvents includes the most minimal events, failing and successful service triggers
|
||||
type BasicEvents interface {
|
||||
// OnSuccess is triggered when a service is successful
|
||||
OnSuccess(*types.Service)
|
||||
// OnFailure is triggered when a service is failing
|
||||
OnFailure(*types.Service, *types.Failure)
|
||||
OnSuccess(*types.Service) // OnSuccess is triggered when a service is successful
|
||||
OnFailure(*types.Service, *types.Failure) // OnFailure is triggered when a service is failing
|
||||
}
|
||||
|
||||
// ServiceEvents are events for Services
|
|
@ -13,7 +13,7 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package notifiers
|
||||
package notifier
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -28,12 +28,11 @@ import (
|
|||
|
||||
var (
|
||||
AllCommunications []types.AllNotifiers
|
||||
Collections *gorm.DB
|
||||
Logs []*NotificationLog
|
||||
db *gorm.DB
|
||||
)
|
||||
|
||||
type Notification struct {
|
||||
Id int64 `gorm:"primary_key column:id" json:"id"`
|
||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||
Method string `gorm:"column:method" json:"method"`
|
||||
Host string `gorm:"not null;column:host" json:"-"`
|
||||
Port int `gorm:"not null;column:port" json:"-"`
|
||||
|
@ -50,7 +49,7 @@ type Notification struct {
|
|||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
Form []NotificationForm `gorm:"-" json:"-"`
|
||||
Routine chan struct{} `gorm:"-" json:"-"`
|
||||
Notifier
|
||||
logs []*NotificationLog `gorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
type NotificationForm struct {
|
||||
|
@ -61,27 +60,43 @@ type NotificationForm struct {
|
|||
}
|
||||
|
||||
type NotificationLog struct {
|
||||
Notifier *Notification
|
||||
Message string
|
||||
Time utils.Timestamp
|
||||
Message string
|
||||
Time utils.Timestamp
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
||||
func AddNotifier(c interface{}) error {
|
||||
if _, ok := c.(Notifier); ok {
|
||||
AllCommunications = append(AllCommunications, c)
|
||||
// db will return the notifier database column/record
|
||||
func (n *Notification) db() *gorm.DB {
|
||||
return db.Model(&Notification{}).Where("method = ?", n.Method).Find(n)
|
||||
}
|
||||
|
||||
// SetDB is called by core to inject the database for a notifier to use
|
||||
func SetDB(d *gorm.DB) {
|
||||
db = d
|
||||
}
|
||||
|
||||
// AddNotifier accept a Notifier interface to be added into the array
|
||||
func AddNotifier(c Notifier) error {
|
||||
if notifier, ok := c.(Notifier); ok {
|
||||
err := checkNotifierForm(notifier)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
AllCommunications = append(AllCommunications, notifier)
|
||||
} else {
|
||||
return errors.New("notifier does not have the required methods")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load is called by core to add all the notifier into memory
|
||||
func Load() []types.AllNotifiers {
|
||||
var notifiers []types.AllNotifiers
|
||||
for _, comm := range AllCommunications {
|
||||
n := comm.(Notifier)
|
||||
n.Init()
|
||||
Init(n)
|
||||
notifiers = append(notifiers, n)
|
||||
n.Test()
|
||||
//n.Test()
|
||||
}
|
||||
return notifiers
|
||||
}
|
||||
|
@ -90,25 +105,22 @@ func (n *Notification) Select() *Notification {
|
|||
return n
|
||||
}
|
||||
|
||||
// Log will record a new notification into memory and will show the logs on the settings page
|
||||
func (n *Notification) Log(msg string) {
|
||||
log := &NotificationLog{
|
||||
Notifier: n,
|
||||
Message: msg,
|
||||
Time: utils.Timestamp(time.Now()),
|
||||
Message: msg,
|
||||
Time: utils.Timestamp(time.Now()),
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
Logs = append(Logs, log)
|
||||
n.logs = append(n.logs, log)
|
||||
}
|
||||
|
||||
// Logs returns an array of the notifiers logs
|
||||
func (n *Notification) Logs() []*NotificationLog {
|
||||
var logs []*NotificationLog
|
||||
for _, v := range Logs {
|
||||
if v.Notifier.Id == n.Id {
|
||||
logs = append(logs, v)
|
||||
}
|
||||
}
|
||||
return reverseLogs(logs)
|
||||
return reverseLogs(n.logs)
|
||||
}
|
||||
|
||||
// reverseLogs will reverse the notifier's logs to be time desc
|
||||
func reverseLogs(input []*NotificationLog) []*NotificationLog {
|
||||
if len(input) == 0 {
|
||||
return input
|
||||
|
@ -116,31 +128,36 @@ func reverseLogs(input []*NotificationLog) []*NotificationLog {
|
|||
return append(reverseLogs(input[1:]), input[0])
|
||||
}
|
||||
|
||||
func (n *Notification) IsInDatabase() bool {
|
||||
return !Collections.Find(n).RecordNotFound()
|
||||
// isInDatabase returns true if the notifier has already been installed
|
||||
func (n *Notification) isInDatabase() bool {
|
||||
inDb := n.db().RecordNotFound()
|
||||
return !inDb
|
||||
}
|
||||
|
||||
func SelectNotification(id int64) (*Notification, error) {
|
||||
// SelectNotification returns the Notification struct from the database
|
||||
func SelectNotification(method string) (*Notification, error) {
|
||||
var notifier Notification
|
||||
err := Collections.Find(¬ifier, id)
|
||||
err := db.Model(&Notification{}).Where("method = ?", method).Scan(¬ifier)
|
||||
return ¬ifier, err.Error
|
||||
}
|
||||
|
||||
// Update will update the notification into the database
|
||||
func (n *Notification) Update() (*Notification, error) {
|
||||
err := Collections.Update(n)
|
||||
err := n.db().Update(n)
|
||||
return n, err.Error
|
||||
}
|
||||
|
||||
func InsertDatabase(n *Notification) (int64, error) {
|
||||
n.CreatedAt = time.Now()
|
||||
// insertDatabase will create a new record into the database for the notifier
|
||||
func insertDatabase(n *Notification) (int64, error) {
|
||||
n.Limits = 3
|
||||
db := Collections.Create(n)
|
||||
if db.Error != nil {
|
||||
return 0, db.Error
|
||||
query := db.Create(n)
|
||||
if query.Error != nil {
|
||||
return 0, query.Error
|
||||
}
|
||||
return n.Id, db.Error
|
||||
return n.Id, query.Error
|
||||
}
|
||||
|
||||
// SelectNotifier returns the Notification struct from the database
|
||||
func SelectNotifier(method string) (*Notification, error) {
|
||||
for _, comm := range AllCommunications {
|
||||
n, ok := comm.(Notifier)
|
||||
|
@ -155,6 +172,7 @@ func SelectNotifier(method string) (*Notification, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// CanSend will return true if notifier has not passed its Limits within the last hour
|
||||
func (f *Notification) CanSend() bool {
|
||||
if f.SentLastHour() >= f.Limits {
|
||||
return false
|
||||
|
@ -162,6 +180,41 @@ func (f *Notification) CanSend() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// Init accepts the Notifier interface to initialize the notifier
|
||||
func Init(n Notifier) (*Notification, error) {
|
||||
err := install(n)
|
||||
var notify *Notification
|
||||
if err == nil {
|
||||
notify, _ = SelectNotification(n.Select().Method)
|
||||
notify.Form = n.Select().Form
|
||||
}
|
||||
return notify, err
|
||||
}
|
||||
|
||||
// install will check the database for the notification, if its not inserted it will insert a new record for it
|
||||
func install(n Notifier) error {
|
||||
inDb := n.Select().isInDatabase()
|
||||
if !inDb {
|
||||
_, err := insertDatabase(n.Select())
|
||||
if err != nil {
|
||||
utils.Log(3, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LastSent returns a time.Duration of the last sent notification for the notifier
|
||||
func (f *Notification) LastSent() time.Duration {
|
||||
if len(f.logs) == 0 {
|
||||
return time.Duration(0)
|
||||
}
|
||||
last := f.Logs()[0]
|
||||
since := time.Since(last.Timestamp)
|
||||
return since
|
||||
}
|
||||
|
||||
// SentLastHour returns the amount of sent notifications within the last hour
|
||||
func (f *Notification) SentLastHour() int {
|
||||
sent := 0
|
||||
hourAgo := time.Now().Add(-1 * time.Hour)
|
||||
|
@ -174,10 +227,12 @@ func (f *Notification) SentLastHour() int {
|
|||
return sent
|
||||
}
|
||||
|
||||
func (f *Notification) LimitValue() int64 {
|
||||
// Limit returns the limits on how many notifications can be sent in 1 hour
|
||||
func (f *Notification) Limit() int64 {
|
||||
return utils.StringInt(f.GetValue("limits"))
|
||||
}
|
||||
|
||||
// GetValue returns the database value of a accept DbField value.
|
||||
func (n *Notification) GetValue(dbField string) string {
|
||||
dbField = strings.ToLower(dbField)
|
||||
switch dbField {
|
||||
|
@ -205,12 +260,20 @@ func (n *Notification) GetValue(dbField string) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func IsType(n interface{}, obj string) bool {
|
||||
// isType will return true if a variable can implement an interface
|
||||
func isType(n interface{}, obj interface{}) bool {
|
||||
objOne := reflect.TypeOf(n)
|
||||
return objOne.String() == obj
|
||||
obj2 := reflect.TypeOf(obj)
|
||||
return objOne.String() == obj2.String()
|
||||
}
|
||||
|
||||
func uniqueStrings(elements []string) []string {
|
||||
// isEnabled returns true if the notifier is enabled
|
||||
func isEnabled(n interface{}) bool {
|
||||
notify := n.(Notifier).Select()
|
||||
return notify.Enabled
|
||||
}
|
||||
|
||||
func UniqueStrings(elements []string) []string {
|
||||
result := []string{}
|
||||
|
||||
for i := 0; i < len(elements); i++ {
|
|
@ -1,3 +1,5 @@
|
|||
// +build bypass
|
||||
|
||||
// Statup
|
||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||
|
@ -13,139 +15,89 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package notifiers
|
||||
package notifier
|
||||
|
||||
import (
|
||||
"github.com/hunterlong/statup/source"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
testNotifier *Tester
|
||||
dir string
|
||||
dir string
|
||||
EXAMPLE_ID = "example"
|
||||
)
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
func (n *Tester) Init() error {
|
||||
return errors.New("im just testing")
|
||||
}
|
||||
|
||||
func (n *Tester) Install() error {
|
||||
return errors.New("installing")
|
||||
}
|
||||
|
||||
func (n *Tester) Run() error {
|
||||
return errors.New("running")
|
||||
}
|
||||
|
||||
func (n *Tester) Select() *Notification {
|
||||
return n.Notification
|
||||
}
|
||||
|
||||
func (n *Tester) OnSuccess(s *types.Service) error {
|
||||
return errors.New(s.Name)
|
||||
}
|
||||
|
||||
func (n *Tester) OnFailure(s *types.Service) error {
|
||||
return errors.New(s.Name)
|
||||
}
|
||||
|
||||
func (n *Tester) Test() error {
|
||||
return errors.New("testing")
|
||||
}
|
||||
|
||||
func init() {
|
||||
dir = utils.Directory
|
||||
utils.InitLogs()
|
||||
}
|
||||
|
||||
func injectDatabase() {
|
||||
dbSession, _ := gorm.Open("sqlite3", dir+"/statup.db")
|
||||
Collections = dbSession.Table("communication").Model(&Notification{})
|
||||
db, _ = gorm.Open("sqlite3", dir+"/statup.db")
|
||||
}
|
||||
|
||||
type Tester struct {
|
||||
*Notification
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
func TestLoad(t *testing.T) {
|
||||
source.Assets()
|
||||
utils.InitLogs()
|
||||
injectDatabase()
|
||||
}
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
testNotifier = &Tester{&Notification{
|
||||
Id: 999999,
|
||||
Method: "tester",
|
||||
Host: "0.0.0.0",
|
||||
Form: []NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Incoming Webhook Url",
|
||||
Placeholder: "Insert your Slack webhook URL here.",
|
||||
DbField: "Host",
|
||||
}}},
|
||||
}
|
||||
|
||||
AddNotifier(testNotifier)
|
||||
AllCommunications = Load()
|
||||
assert.Len(t, AllCommunications, 1)
|
||||
}
|
||||
|
||||
func TestIsInDatabase(t *testing.T) {
|
||||
in := testNotifier.IsInDatabase()
|
||||
assert.False(t, in)
|
||||
in := example.isInDatabase()
|
||||
assert.True(t, in)
|
||||
}
|
||||
|
||||
func TestInsertDatabase(t *testing.T) {
|
||||
newId, err := InsertDatabase(testNotifier.Notification)
|
||||
_, err := insertDatabase(example.Notification)
|
||||
assert.Nil(t, err)
|
||||
assert.NotZero(t, newId)
|
||||
assert.NotZero(t, example.Id)
|
||||
|
||||
in := testNotifier.IsInDatabase()
|
||||
in := example.isInDatabase()
|
||||
assert.True(t, in)
|
||||
}
|
||||
|
||||
func TestSelectNotification(t *testing.T) {
|
||||
notifier, err := SelectNotification(999999)
|
||||
notifier, err := SelectNotification(EXAMPLE_ID)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "tester", notifier.Method)
|
||||
assert.Equal(t, "example", notifier.Method)
|
||||
assert.False(t, notifier.Enabled)
|
||||
}
|
||||
|
||||
func TestNotification_Update(t *testing.T) {
|
||||
notifier, err := SelectNotification(999999)
|
||||
notifier, err := SelectNotification(EXAMPLE_ID)
|
||||
assert.Nil(t, err)
|
||||
notifier.Method = "updatedName"
|
||||
notifier.Host = "new host here"
|
||||
notifier.Enabled = true
|
||||
updated, err := notifier.Update()
|
||||
assert.Nil(t, err)
|
||||
selected, err := SelectNotification(updated.Id)
|
||||
selected, err := SelectNotification(updated.Method)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "updatedName", selected.Method)
|
||||
assert.Equal(t, "new host here", selected.GetValue("host"))
|
||||
assert.True(t, selected.Enabled)
|
||||
}
|
||||
|
||||
func TestNotification_GetValue(t *testing.T) {
|
||||
notifier, err := SelectNotification(999999)
|
||||
notifier, err := SelectNotification(EXAMPLE_ID)
|
||||
assert.Nil(t, err)
|
||||
val := notifier.GetValue("Host")
|
||||
assert.Equal(t, "0.0.0.0", val)
|
||||
assert.Equal(t, "http://exmaplehost.com", val)
|
||||
}
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
err := testNotifier.Run()
|
||||
assert.Equal(t, "running", err.Error())
|
||||
}
|
||||
//func TestRun(t *testing.T) {
|
||||
// err := example.Run()
|
||||
// assert.Equal(t, "running", err.Error())
|
||||
//}
|
||||
|
||||
func TestTestIt(t *testing.T) {
|
||||
err := testNotifier.Test()
|
||||
assert.Equal(t, "testing", err.Error())
|
||||
}
|
||||
//func TestTestIt(t *testing.T) {
|
||||
// err := example.Test()
|
||||
// assert.Equal(t, "testing", err.Error())
|
||||
//}
|
||||
|
||||
func TestOnSuccess(t *testing.T) {
|
||||
s := &types.Service{
|
|
@ -18,7 +18,7 @@ package core
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/hunterlong/statup/notifiers"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"sort"
|
||||
|
@ -30,6 +30,10 @@ type Service struct {
|
|||
*types.Service
|
||||
}
|
||||
|
||||
func (s *Service) Select() *types.Service {
|
||||
return s.Service
|
||||
}
|
||||
|
||||
func ReturnService(s *types.Service) *Service {
|
||||
return &Service{s}
|
||||
}
|
||||
|
@ -37,7 +41,7 @@ func ReturnService(s *types.Service) *Service {
|
|||
// SelectService returns a *core.Service from in memory
|
||||
func SelectService(id int64) *Service {
|
||||
for _, s := range CoreApp.Services {
|
||||
if s.(*Service).Id == id {
|
||||
if s.Select().Id == id {
|
||||
return s.(*Service)
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +62,7 @@ func (c *Core) SelectAllServices() ([]*Service, error) {
|
|||
service.AllFailures()
|
||||
CoreApp.Services = append(CoreApp.Services, service)
|
||||
}
|
||||
reorderServices()
|
||||
sort.Sort(ServiceOrder(CoreApp.Services))
|
||||
return services, db.Error
|
||||
}
|
||||
|
||||
|
@ -265,7 +269,7 @@ func (u *Service) Delete() error {
|
|||
slice := CoreApp.Services
|
||||
CoreApp.Services = append(slice[:i], slice[i+1:]...)
|
||||
reorderServices()
|
||||
notifiers.OnDeletedService(u.Service)
|
||||
notifier.OnDeletedService(u.Service)
|
||||
return err.Error
|
||||
}
|
||||
|
||||
|
@ -289,7 +293,7 @@ func (u *Service) Update(restart bool) error {
|
|||
}
|
||||
reorderServices()
|
||||
updateService(u)
|
||||
notifiers.OnUpdatedService(u.Service)
|
||||
notifier.OnUpdatedService(u.Service)
|
||||
return err.Error
|
||||
}
|
||||
|
||||
|
@ -305,7 +309,7 @@ func (u *Service) Create() (int64, error) {
|
|||
go u.CheckQueue(true)
|
||||
CoreApp.Services = append(CoreApp.Services, u)
|
||||
reorderServices()
|
||||
notifiers.OnNewService(u.Service)
|
||||
notifier.OnNewService(u.Service)
|
||||
return u.Id, nil
|
||||
}
|
||||
|
||||
|
@ -318,7 +322,7 @@ func (c *Core) ServicesCount() int {
|
|||
func (c *Core) CountOnline() int {
|
||||
amount := 0
|
||||
for _, s := range CoreApp.Services {
|
||||
if s.(*Service).Online {
|
||||
if s.Select().Online {
|
||||
amount++
|
||||
}
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@ INSERT INTO failures (issue,method,service,created_at) VALUES
|
|||
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14'),
|
||||
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14'),
|
||||
('HTTP Status Code 200 did not match 0','',18,'2018-08-31 10:42:14');
|
||||
INSERT INTO communication (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
|
||||
INSERT INTO notifications (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
|
||||
(1,'email','smtp.emailer.com',587,'exampleuser','password123','info@betatude.com','sendto@gmail.com','','',1,0,7,'2018-08-31 10:42:15'),
|
||||
(2,'slack','https://webhooksurl.slack.com/***',0,'','','','','','',0,0,3,'2018-08-31 10:42:08'),
|
||||
(3,'twilio','',0,'','','','','','',0,0,3,'2018-08-31 10:42:08');
|
||||
|
|
|
@ -133,7 +133,7 @@ INSERT INTO failures (issue,method,service,created_at) VALUES
|
|||
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.271162743-07:00'),
|
||||
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.272209564-07:00'),
|
||||
('HTTP Status Code 200 did not match 0','',18,'2018-08-31 10:42:14.271162743-07:00');
|
||||
INSERT INTO communication (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
|
||||
INSERT INTO notifications (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
|
||||
(1,'email','smtp.emailer.com',587,'exampleuser','password123','info@betatude.com','sendto@gmail.com','','',true,false,7,'2018-08-31 10:42:15.000829706-07:00'),
|
||||
(2,'slack','https://webhooksurl.slack.com/***',0,'','','','','','',false,false,3,'2018-08-31 10:42:08.775366824-07:00'),
|
||||
(3,'twilio','',0,'','','','','','',false,false,3,'2018-08-31 10:42:08.776944923-07:00');
|
||||
|
|
|
@ -133,7 +133,7 @@ INSERT INTO failures (issue,method,service,created_at) VALUES
|
|||
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.271162743-07:00'),
|
||||
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.272209564-07:00'),
|
||||
('HTTP Status Code 200 did not match 0','',18,'2018-08-31 10:42:14.271162743-07:00');
|
||||
INSERT INTO communication (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
|
||||
INSERT INTO notifications (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
|
||||
(1,'email','smtp.emailer.com',587,'exampleuser','password123','info@betatude.com','sendto@gmail.com','','',1,0,7,'2018-08-31 10:42:15.000829706-07:00'),
|
||||
(2,'slack','https://webhooksurl.slack.com/***',0,'','','','','','',0,0,3,'2018-08-31 10:42:08.775366824-07:00'),
|
||||
(3,'twilio','',0,'','','','','','',0,0,3,'2018-08-31 10:42:08.776944923-07:00');
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/hunterlong/statup/core"
|
||||
"github.com/hunterlong/statup/notifiers"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/source"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"net/http"
|
||||
|
@ -147,7 +147,7 @@ func SaveNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
apiSecret := form.Get("api_secret")
|
||||
limits := int(utils.StringInt(form.Get("limits")))
|
||||
|
||||
notifer, err := notifiers.SelectNotifier(method)
|
||||
notifer, err := notifier.SelectNotifier(method)
|
||||
if err != nil {
|
||||
utils.Log(3, fmt.Sprintf("issue saving notifier %v: %v", method, err))
|
||||
ExecuteResponse(w, r, "settings.html", core.CoreApp, "/settings")
|
||||
|
@ -186,6 +186,6 @@ func SaveNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
|||
if err != nil {
|
||||
utils.Log(3, fmt.Sprintf("issue updating notifier: %v", err))
|
||||
}
|
||||
notifiers.OnSave(notifer.Method)
|
||||
notifier.OnSave(notifer.Method)
|
||||
ExecuteResponse(w, r, "settings.html", core.CoreApp, "/settings")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
// Statup
|
||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
||||
//
|
||||
// https://github.com/hunterlong/statup
|
||||
//
|
||||
// The licenses for most software and other practical works are designed
|
||||
// to take away your freedom to share and change the works. By contrast,
|
||||
// the GNU General Public License is intended to guarantee your freedom to
|
||||
// share and change all versions of a program--to make sure it remains free
|
||||
// software for all its users.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package notifiers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
DISCORD_METHOD = "discord"
|
||||
DISCORD_TEST = `{"content": "This is a notification from Statup!"}`
|
||||
)
|
||||
|
||||
type Discord struct {
|
||||
*notifier.Notification
|
||||
}
|
||||
|
||||
var discorder = &Discord{¬ifier.Notification{
|
||||
Method: DISCORD_METHOD,
|
||||
Host: "https://discordapp.com/api/webhooks/****/*****",
|
||||
Form: []notifier.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Discord Webhook URL",
|
||||
Placeholder: "Insert your webhook URL here",
|
||||
DbField: "host",
|
||||
}}},
|
||||
}
|
||||
|
||||
// init the Discord notifier
|
||||
func init() {
|
||||
err := notifier.AddNotifier(discorder)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (u *Discord) Test() error {
|
||||
utils.Log(1, "Discord notifier loaded")
|
||||
discordPost([]byte(DISCORD_TEST))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Discord won't be using the Run() process
|
||||
func (u *Discord) Run() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Discord won't be using the Run() process
|
||||
func (u *Discord) Select() *notifier.Notification {
|
||||
return u.Notification
|
||||
}
|
||||
|
||||
// discordPost sends an HTTP POST to the webhook URL
|
||||
func discordPost(msg []byte) {
|
||||
req, _ := http.NewRequest("POST", discorder.GetValue("host"), bytes.NewBuffer(msg))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
utils.Log(3, fmt.Sprintf("issue sending Discord message to channel: %v", err))
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
discorder.Log(string(msg))
|
||||
}
|
||||
|
||||
func (u *Discord) OnFailure(s *types.Service, f *types.Failure) {
|
||||
msg := fmt.Sprintf(`{"content": "Your service '%v' is currently failing! Reason: %v"}`, s.Name, f.Issue)
|
||||
discordPost([]byte(msg))
|
||||
}
|
||||
|
||||
func (u *Discord) OnSuccess(s *types.Service) {
|
||||
|
||||
}
|
||||
|
||||
func (u *Discord) OnSave() error {
|
||||
msg := fmt.Sprintf(`{"content": "The Discord notifier on Statup was just updated."}`)
|
||||
discordPost([]byte(msg))
|
||||
return nil
|
||||
}
|
|
@ -17,9 +17,9 @@ package notifiers
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/GeertJohan/go.rice"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"gopkg.in/gomail.v2"
|
||||
|
@ -33,7 +33,6 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
emailer *Email
|
||||
emailArray []string
|
||||
emailQueue []*EmailOutgoing
|
||||
emailBox *rice.Box
|
||||
|
@ -41,78 +40,53 @@ var (
|
|||
)
|
||||
|
||||
type Email struct {
|
||||
*Notification
|
||||
*notifier.Notification
|
||||
}
|
||||
|
||||
var emailer = &Email{
|
||||
Notification: ¬ifier.Notification{
|
||||
Method: EMAIL_METHOD,
|
||||
Form: []notifier.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "SMTP Host",
|
||||
Placeholder: "Insert your SMTP Host here.",
|
||||
DbField: "Host",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "SMTP Username",
|
||||
Placeholder: "Insert your SMTP Username here.",
|
||||
DbField: "Username",
|
||||
}, {
|
||||
Type: "password",
|
||||
Title: "SMTP Password",
|
||||
Placeholder: "Insert your SMTP Password here.",
|
||||
DbField: "Password",
|
||||
}, {
|
||||
Type: "number",
|
||||
Title: "SMTP Port",
|
||||
Placeholder: "Insert your SMTP Port here.",
|
||||
DbField: "Port",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "Outgoing Email Address",
|
||||
Placeholder: "Insert your Outgoing Email Address",
|
||||
DbField: "Var1",
|
||||
}, {
|
||||
Type: "email",
|
||||
Title: "Send Alerts To",
|
||||
Placeholder: "Email Address",
|
||||
DbField: "Var2",
|
||||
}},
|
||||
}}
|
||||
|
||||
// DEFINE YOUR NOTIFICATION HERE.
|
||||
func init() {
|
||||
|
||||
emailer = &Email{
|
||||
Notification: &Notification{
|
||||
Id: EMAIL_ID,
|
||||
Method: EMAIL_METHOD,
|
||||
Form: []NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "SMTP Host",
|
||||
Placeholder: "Insert your SMTP Host here.",
|
||||
DbField: "Host",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "SMTP Username",
|
||||
Placeholder: "Insert your SMTP Username here.",
|
||||
DbField: "Username",
|
||||
}, {
|
||||
Type: "password",
|
||||
Title: "SMTP Password",
|
||||
Placeholder: "Insert your SMTP Password here.",
|
||||
DbField: "Password",
|
||||
}, {
|
||||
Type: "number",
|
||||
Title: "SMTP Port",
|
||||
Placeholder: "Insert your SMTP Port here.",
|
||||
DbField: "Port",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "Outgoing Email Address",
|
||||
Placeholder: "Insert your Outgoing Email Address",
|
||||
DbField: "Var1",
|
||||
}, {
|
||||
Type: "email",
|
||||
Title: "Send Alerts To",
|
||||
Placeholder: "Email Address",
|
||||
DbField: "Var2",
|
||||
}},
|
||||
}}
|
||||
|
||||
err := AddNotifier(emailer)
|
||||
err := notifier.AddNotifier(emailer)
|
||||
if err != nil {
|
||||
utils.Log(3, err)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// WHEN NOTIFIER LOADS
|
||||
func (u *Email) Init() error {
|
||||
emailBox = rice.MustFindBox("emails")
|
||||
err := u.Install()
|
||||
utils.Log(1, fmt.Sprintf("Creating Mailer: %v:%v", u.Notification.Host, u.Notification.Port))
|
||||
|
||||
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))
|
||||
mailer = gomail.NewPlainDialer(u.Notification.Host, u.Notification.Port, u.Notification.Username, u.Notification.Password)
|
||||
mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||
|
||||
go u.Run()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *Email) Test() error {
|
||||
utils.Log(1, "Emailer notifier loaded")
|
||||
if u.Enabled {
|
||||
|
@ -200,20 +174,6 @@ func (u *Email) OnSave() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
|
||||
func (u *Email) Install() error {
|
||||
inDb := 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 nil
|
||||
}
|
||||
|
||||
func (u *Email) dialSend(email *EmailOutgoing) error {
|
||||
m := gomail.NewMessage()
|
||||
m.SetHeader("From", email.From)
|
||||
|
|
|
@ -17,6 +17,7 @@ package notifiers
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"net/http"
|
||||
|
@ -31,27 +32,26 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
lineNotify *LineNotify
|
||||
lineNotifyMessages []string
|
||||
)
|
||||
|
||||
type LineNotify struct {
|
||||
*Notification
|
||||
*notifier.Notification
|
||||
}
|
||||
|
||||
var lineNotify = &LineNotify{¬ifier.Notification{
|
||||
Method: LINE_NOTIFY_METHOD,
|
||||
Form: []notifier.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Access Token",
|
||||
Placeholder: "Insert your Line Notify Access Token here.",
|
||||
DbField: "api_secret",
|
||||
}}},
|
||||
}
|
||||
|
||||
// DEFINE YOUR NOTIFICATION HERE.
|
||||
func init() {
|
||||
lineNotify = &LineNotify{&Notification{
|
||||
Id: LINE_NOTIFY_ID,
|
||||
Method: LINE_NOTIFY_METHOD,
|
||||
Form: []NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Access Token",
|
||||
Placeholder: "Insert your Line Notify Access Token here.",
|
||||
DbField: "api_secret",
|
||||
}}},
|
||||
}
|
||||
err := AddNotifier(lineNotify)
|
||||
err := notifier.AddNotifier(lineNotify)
|
||||
if err != nil {
|
||||
utils.Log(3, err)
|
||||
}
|
||||
|
@ -61,22 +61,6 @@ func (u *LineNotify) postUrl() string {
|
|||
return fmt.Sprintf("https://notify-api.line.me/api/notify")
|
||||
}
|
||||
|
||||
// WHEN NOTIFIER LOADS
|
||||
func (u *LineNotify) 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 *LineNotify) Test() error {
|
||||
msg := fmt.Sprintf("You're Statup Line Notify Notifier is working correctly!")
|
||||
SendLineNotify(msg)
|
||||
|
@ -85,7 +69,7 @@ func (u *LineNotify) Test() error {
|
|||
|
||||
// AFTER NOTIFIER LOADS, IF ENABLED, START A QUEUE PROCESS
|
||||
func (u *LineNotify) Run() error {
|
||||
lineNotifyMessages = uniqueStrings(lineNotifyMessages)
|
||||
lineNotifyMessages = notifier.UniqueStrings(lineNotifyMessages)
|
||||
for _, msg := range lineNotifyMessages {
|
||||
|
||||
if u.CanSend() {
|
||||
|
@ -142,18 +126,3 @@ func (u *LineNotify) OnSave() error {
|
|||
// Do updating stuff here
|
||||
return nil
|
||||
}
|
||||
|
||||
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
|
||||
func (u *LineNotify) Install() error {
|
||||
var err error
|
||||
inDb := lineNotify.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
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package notifiers
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"net/http"
|
||||
|
@ -35,13 +36,12 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
slacker *Slack
|
||||
slackMessages []string
|
||||
messageLock *sync.Mutex
|
||||
)
|
||||
|
||||
type Slack struct {
|
||||
*Notification
|
||||
*notifier.Notification
|
||||
}
|
||||
|
||||
type slackMessage struct {
|
||||
|
@ -49,40 +49,24 @@ type slackMessage struct {
|
|||
Time int64
|
||||
}
|
||||
|
||||
// DEFINE YOUR NOTIFICATION HERE.
|
||||
func init() {
|
||||
slacker = &Slack{&Notification{
|
||||
Id: SLACK_ID,
|
||||
Method: SLACK_METHOD,
|
||||
Host: "https://webhooksurl.slack.com/***",
|
||||
Form: []NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Incoming Webhook Url",
|
||||
Placeholder: "Insert your Slack webhook URL here.",
|
||||
DbField: "Host",
|
||||
}}},
|
||||
}
|
||||
messageLock = new(sync.Mutex)
|
||||
err := AddNotifier(slacker)
|
||||
if err != nil {
|
||||
utils.Log(3, err)
|
||||
}
|
||||
var slacker = &Slack{¬ifier.Notification{
|
||||
Method: SLACK_METHOD,
|
||||
Host: "https://webhooksurl.slack.com/***",
|
||||
Form: []notifier.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Incoming Webhook Url",
|
||||
Placeholder: "Insert your Slack webhook URL here.",
|
||||
DbField: "Host",
|
||||
}}},
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
// DEFINE YOUR NOTIFICATION HERE.
|
||||
func init() {
|
||||
err := notifier.AddNotifier(slacker)
|
||||
messageLock = new(sync.Mutex)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *Slack) Test() error {
|
||||
|
@ -95,7 +79,7 @@ func (u *Slack) Test() error {
|
|||
// AFTER NOTIFIER LOADS, IF ENABLED, START A QUEUE PROCESS
|
||||
func (u *Slack) Run() error {
|
||||
messageLock.Lock()
|
||||
slackMessages = uniqueStrings(slackMessages)
|
||||
slackMessages = notifier.UniqueStrings(slackMessages)
|
||||
for _, msg := range slackMessages {
|
||||
|
||||
if u.CanSend() {
|
||||
|
@ -125,6 +109,7 @@ func SendSlack(temp string, data interface{}) error {
|
|||
slackTemp.Execute(buf, data)
|
||||
slackMessages = append(slackMessages, buf.String())
|
||||
messageLock.Unlock()
|
||||
slacker.Log(buf.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -151,17 +136,3 @@ func (u *Slack) OnSave() error {
|
|||
u.Test()
|
||||
return nil
|
||||
}
|
||||
|
||||
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
|
||||
func (u *Slack) Install() error {
|
||||
inDb := 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 nil
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package notifiers
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hunterlong/statup/core/notifier"
|
||||
"github.com/hunterlong/statup/types"
|
||||
"github.com/hunterlong/statup/utils"
|
||||
"net/http"
|
||||
|
@ -31,49 +32,43 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
twilio *Twilio
|
||||
twilioMessages []string
|
||||
)
|
||||
|
||||
type Twilio struct {
|
||||
*Notification
|
||||
*notifier.Notification
|
||||
}
|
||||
|
||||
type twilioMessage struct {
|
||||
Service *types.Service
|
||||
Time int64
|
||||
var twilio = &Twilio{¬ifier.Notification{
|
||||
Method: TWILIO_METHOD,
|
||||
Form: []notifier.NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Account Sid",
|
||||
Placeholder: "Insert your Twilio Account Sid",
|
||||
DbField: "api_key",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "Account Token",
|
||||
Placeholder: "Insert your Twilio Account Token",
|
||||
DbField: "api_secret",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "SMS to Phone Number",
|
||||
Placeholder: "+18555555555",
|
||||
DbField: "Var1",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "From Phone Number",
|
||||
Placeholder: "+18555555555",
|
||||
DbField: "Var2",
|
||||
}}},
|
||||
}
|
||||
|
||||
// DEFINE YOUR NOTIFICATION HERE.
|
||||
func init() {
|
||||
twilio = &Twilio{&Notification{
|
||||
Id: TWILIO_ID,
|
||||
Method: TWILIO_METHOD,
|
||||
Form: []NotificationForm{{
|
||||
Type: "text",
|
||||
Title: "Account Sid",
|
||||
Placeholder: "Insert your Twilio Account Sid",
|
||||
DbField: "api_key",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "Account Token",
|
||||
Placeholder: "Insert your Twilio Account Token",
|
||||
DbField: "api_secret",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "SMS to Phone Number",
|
||||
Placeholder: "+18555555555",
|
||||
DbField: "Var1",
|
||||
}, {
|
||||
Type: "text",
|
||||
Title: "From Phone Number",
|
||||
Placeholder: "+18555555555",
|
||||
DbField: "Var2",
|
||||
}}},
|
||||
}
|
||||
err := AddNotifier(twilio)
|
||||
err := notifier.AddNotifier(twilio)
|
||||
if err != nil {
|
||||
utils.Log(3, err)
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,22 +76,6 @@ func (u *Twilio) postUrl() string {
|
|||
return fmt.Sprintf("https://api.twilio.com/2010-04-01/Accounts/%v/Messages.json", u.ApiKey)
|
||||
}
|
||||
|
||||
// WHEN NOTIFIER LOADS
|
||||
func (u *Twilio) 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 *Twilio) Test() error {
|
||||
utils.Log(1, "Twilio notifier loaded")
|
||||
msg := fmt.Sprintf("You're Statup Twilio Notifier is working correctly!")
|
||||
|
@ -106,7 +85,7 @@ func (u *Twilio) Test() error {
|
|||
|
||||
// AFTER NOTIFIER LOADS, IF ENABLED, START A QUEUE PROCESS
|
||||
func (u *Twilio) Run() error {
|
||||
twilioMessages = uniqueStrings(twilioMessages)
|
||||
twilioMessages = notifier.UniqueStrings(twilioMessages)
|
||||
for _, msg := range twilioMessages {
|
||||
|
||||
if u.CanSend() {
|
||||
|
@ -167,17 +146,3 @@ func (u *Twilio) OnSave() error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
|
||||
func (u *Twilio) Install() error {
|
||||
inDb := twilio.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 nil
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<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" 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>
|
||||
{{ range .Communications }}
|
||||
{{ range .Notifications }}
|
||||
<a class="nav-link text-capitalize" id="v-pills-{{underscore .Select.Method}}-tab" data-toggle="pill" href="#v-pills-{{underscore .Select.Method}}" role="tab" aria-controls="v-pills-{{underscore .Select.Method}}" aria-selected="false">{{.Select.Method}}</a>
|
||||
{{ 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>
|
||||
|
@ -132,7 +132,7 @@
|
|||
{{end}}
|
||||
</div>
|
||||
|
||||
{{ range .Communications }}
|
||||
{{ range .Notifications }}
|
||||
{{$n := .Select}}
|
||||
<div class="tab-pane" id="v-pills-{{underscore $n.Method}}" role="tabpanel" aria-labelledby="v-pills-{{underscore $n.Method }}-tab">
|
||||
<form method="POST" action="/settings/notifier/{{ $n.Method }}">
|
||||
|
@ -145,7 +145,7 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label class="text-capitalize" for="limits_per_hour_{{underscore $n.Method }}">Limits per Hour</label>
|
||||
<input type="number" name="limits" class="form-control" value="{{$n.LimitValue}}" id="limits_per_hour_{{underscore $n.Method }}" min="1" max="60" placeholder="How many messages can send per hour">
|
||||
<input type="number" name="limits" class="form-control" value="{{$n.Limits}}" id="limits_per_hour_{{underscore $n.Method }}" min="1" max="60" placeholder="How many messages can send per hour">
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
|
|
|
@ -4,31 +4,33 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
type AllNotifiers interface{}
|
||||
|
||||
// Core struct contains all the required fields for Statup. All application settings
|
||||
// will be saved into 1 row in the 'core' table. You can use the core.CoreApp
|
||||
// global variable to interact with the attributes to the application, such as services.
|
||||
type Core struct {
|
||||
Name string `gorm:"not null;column:name" json:"name"`
|
||||
Description string `gorm:"not null;column:description" json:"description,omitempty"`
|
||||
Config string `gorm:"column:config" json:"-"`
|
||||
ApiKey string `gorm:"column:api_key" json:"-"`
|
||||
ApiSecret string `gorm:"column:api_secret" json:"-"`
|
||||
Style string `gorm:"not null;column:style" json:"style,omitempty"`
|
||||
Footer string `gorm:"not null;column:footer" json:"footer,omitempty"`
|
||||
Domain string `gorm:"not null;column:domain" json:"domain,omitempty"`
|
||||
Version string `gorm:"column:version" json:"version"`
|
||||
MigrationId int64 `gorm:"column:migration_id" json:"migration_id,omitempty"`
|
||||
UseCdn bool `gorm:"column:use_cdn;default:false" json:"using_cdn,omitempty"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
DbConnection string `gorm:"-" json:"database"`
|
||||
Started time.Time `gorm:"-" json:"started_on"`
|
||||
Services []ServiceInterface `gorm:"-" json:"services,omitempty"`
|
||||
Plugins []Info `gorm:"-" json:"-"`
|
||||
Repos []PluginJSON `gorm:"-" json:"-"`
|
||||
AllPlugins []PluginActions `gorm:"-" json:"-"`
|
||||
Communications []AllNotifiers `gorm:"-" json:"-"`
|
||||
CoreInterface `gorm:"-" json:"-"`
|
||||
Name string `gorm:"not null;column:name" json:"name"`
|
||||
Description string `gorm:"not null;column:description" json:"description,omitempty"`
|
||||
Config string `gorm:"column:config" json:"-"`
|
||||
ApiKey string `gorm:"column:api_key" json:"-"`
|
||||
ApiSecret string `gorm:"column:api_secret" json:"-"`
|
||||
Style string `gorm:"not null;column:style" json:"style,omitempty"`
|
||||
Footer string `gorm:"not null;column:footer" json:"footer,omitempty"`
|
||||
Domain string `gorm:"not null;column:domain" json:"domain,omitempty"`
|
||||
Version string `gorm:"column:version" json:"version"`
|
||||
MigrationId int64 `gorm:"column:migration_id" json:"migration_id,omitempty"`
|
||||
UseCdn bool `gorm:"column:use_cdn;default:false" json:"using_cdn,omitempty"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
DbConnection string `gorm:"-" json:"database"`
|
||||
Started time.Time `gorm:"-" json:"started_on"`
|
||||
Services []ServiceInterface `gorm:"-" json:"services,omitempty"`
|
||||
Plugins []Info `gorm:"-" json:"-"`
|
||||
Repos []PluginJSON `gorm:"-" json:"-"`
|
||||
AllPlugins []PluginActions `gorm:"-" json:"-"`
|
||||
Notifications []AllNotifiers `gorm:"-" json:"-"`
|
||||
CoreInterface `gorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
type CoreInterface interface {
|
||||
|
|
130
types/service.go
130
types/service.go
|
@ -20,75 +20,83 @@ import (
|
|||
)
|
||||
|
||||
type Service struct {
|
||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
Domain string `gorm:"column:domain" json:"domain"`
|
||||
Expected string `gorm:"not null;column:expected" json:"expected"`
|
||||
ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status"`
|
||||
Interval int `gorm:"default:30;column:check_interval" json:"check_interval"`
|
||||
Type string `gorm:"column:check_type" json:"type"`
|
||||
Method string `gorm:"column:method" json:"method"`
|
||||
PostData string `gorm:"not null;column:post_data" json:"post_data"`
|
||||
Port int `gorm:"not null;column:port" json:"port"`
|
||||
Timeout int `gorm:"default:30;column:timeout" json:"timeout"`
|
||||
Order int `gorm:"default:0;column:order_id" json:"order_id"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
Online bool `gorm:"-" json:"online"`
|
||||
Latency float64 `gorm:"-" json:"latency"`
|
||||
Online24Hours float32 `gorm:"-" json:"24_hours_online"`
|
||||
AvgResponse string `gorm:"-" json:"avg_response"`
|
||||
Failures []interface{} `gorm:"-" json:"failures"`
|
||||
Checkins []*Checkin `gorm:"-" json:"checkins"`
|
||||
Running chan bool `gorm:"-" json:"-"`
|
||||
Checkpoint time.Time `gorm:"-" json:"-"`
|
||||
SleepDuration time.Duration `gorm:"-" json:"-"`
|
||||
LastResponse string `gorm:"-" json:"-"`
|
||||
LastStatusCode int `gorm:"-" json:"status_code"`
|
||||
LastOnline time.Time `gorm:"-" json:"last_online"`
|
||||
DnsLookup float64 `gorm:"-" json:"dns_lookup_time"`
|
||||
ServiceInterface `gorm:"-" json:"-"`
|
||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
Domain string `gorm:"column:domain" json:"domain"`
|
||||
Expected string `gorm:"not null;column:expected" json:"expected"`
|
||||
ExpectedStatus int `gorm:"default:200;column:expected_status" json:"expected_status"`
|
||||
Interval int `gorm:"default:30;column:check_interval" json:"check_interval"`
|
||||
Type string `gorm:"column:check_type" json:"type"`
|
||||
Method string `gorm:"column:method" json:"method"`
|
||||
PostData string `gorm:"not null;column:post_data" json:"post_data"`
|
||||
Port int `gorm:"not null;column:port" json:"port"`
|
||||
Timeout int `gorm:"default:30;column:timeout" json:"timeout"`
|
||||
Order int `gorm:"default:0;column:order_id" json:"order_id"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
Online bool `gorm:"-" json:"online"`
|
||||
Latency float64 `gorm:"-" json:"latency"`
|
||||
Online24Hours float32 `gorm:"-" json:"24_hours_online"`
|
||||
AvgResponse string `gorm:"-" json:"avg_response"`
|
||||
Failures []interface{} `gorm:"-" json:"failures"`
|
||||
Checkins []*Checkin `gorm:"-" json:"checkins"`
|
||||
Running chan bool `gorm:"-" json:"-"`
|
||||
Checkpoint time.Time `gorm:"-" json:"-"`
|
||||
SleepDuration time.Duration `gorm:"-" json:"-"`
|
||||
LastResponse string `gorm:"-" json:"-"`
|
||||
LastStatusCode int `gorm:"-" json:"status_code"`
|
||||
LastOnline time.Time `gorm:"-" json:"last_online"`
|
||||
DnsLookup float64 `gorm:"-" json:"dns_lookup_time"`
|
||||
}
|
||||
|
||||
type ServiceInterface interface {
|
||||
// Database functions
|
||||
Select() *Service
|
||||
CheckQueue(bool)
|
||||
Check(bool)
|
||||
Create() (int64, error)
|
||||
Update(bool) error
|
||||
Delete() error
|
||||
// Basic Method functions
|
||||
AvgTime() float64
|
||||
OnlineSince(time.Time) float32
|
||||
Online24() float32
|
||||
SmallText() string
|
||||
GraphData() string
|
||||
AvgUptime(time.Time) string
|
||||
AvgUptime24() string
|
||||
ToJSON() string
|
||||
// Failure functions
|
||||
CreateFailure(*Failure) (int64, error)
|
||||
//LimitedFailures() []interface{}
|
||||
//AllFailures() []*Failure
|
||||
TotalFailuresSince(time.Time) (uint64, error)
|
||||
TotalFailures24() (uint64, error)
|
||||
TotalFailures() (uint64, error)
|
||||
DeleteFailures()
|
||||
// Hits functions (successful responses)
|
||||
CreateHit(*Hit) (int64, error)
|
||||
Hits() ([]*Hit, error)
|
||||
TotalHits() (uint64, error)
|
||||
TotalHitsSince(time.Time) (uint64, error)
|
||||
Sum() (float64, error)
|
||||
LimitedHits() ([]*Hit, error)
|
||||
SelectHitsGroupBy(string) ([]*Hit, error)
|
||||
// Go Routines
|
||||
CheckQueue(bool)
|
||||
Check(bool)
|
||||
//checkHttp(bool) *Service
|
||||
//checkTcp(bool) *Service
|
||||
// Checkin functions
|
||||
AllCheckins() []*Checkin
|
||||
}
|
||||
|
||||
//type ServiceInterface interface {
|
||||
// // Database functions
|
||||
// Create() (int64, error)
|
||||
// Update(bool) error
|
||||
// Delete() error
|
||||
// // Basic Method functions
|
||||
// AvgTime() float64
|
||||
// OnlineSince(time.Time) float32
|
||||
// Online24() float32
|
||||
// SmallText() string
|
||||
// GraphData() string
|
||||
// AvgUptime(time.Time) string
|
||||
// AvgUptime24() string
|
||||
// ToJSON() string
|
||||
// // Failure functions
|
||||
// CreateFailure(*Failure) (int64, error)
|
||||
// //LimitedFailures() []interface{}
|
||||
// //AllFailures() []*Failure
|
||||
// TotalFailuresSince(time.Time) (uint64, error)
|
||||
// TotalFailures24() (uint64, error)
|
||||
// TotalFailures() (uint64, error)
|
||||
// DeleteFailures()
|
||||
// // Hits functions (successful responses)
|
||||
// CreateHit(*Hit) (int64, error)
|
||||
// Hits() ([]*Hit, error)
|
||||
// TotalHits() (uint64, error)
|
||||
// TotalHitsSince(time.Time) (uint64, error)
|
||||
// Sum() (float64, error)
|
||||
// LimitedHits() ([]*Hit, error)
|
||||
// SelectHitsGroupBy(string) ([]*Hit, error)
|
||||
// // Go Routines
|
||||
// CheckQueue(bool)
|
||||
// Check(bool)
|
||||
// //checkHttp(bool) *Service
|
||||
// //checkTcp(bool) *Service
|
||||
// // Checkin functions
|
||||
// //AllCheckins() []*Checkin
|
||||
//}
|
||||
|
||||
// Start will create a channel for the service checking go routine
|
||||
func (s *Service) Start() {
|
||||
s.Running = make(chan bool)
|
||||
|
|
|
@ -21,12 +21,10 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
type AllNotifiers interface{}
|
||||
|
||||
// Hit struct is a 'successful' ping or web response entry for a service.
|
||||
type Hit struct {
|
||||
Id int64 `gorm:"primary_key;column:id"`
|
||||
Service int64 `gorm:"index;column:service"`
|
||||
Service int64 `gorm:"column:service"`
|
||||
Latency float64 `gorm:"column:latency"`
|
||||
CreatedAt time.Time `gorm:"column:created_at"`
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue