mirror of https://github.com/statping/statping
pull/429/head
parent
a14fb1f616
commit
71b7254fce
5
Makefile
5
Makefile
|
@ -20,6 +20,9 @@ up:
|
||||||
down:
|
down:
|
||||||
docker-compose -f docker-compose.yml -f dev/docker-compose.full.yml down --volumes --remove-orphans
|
docker-compose -f docker-compose.yml -f dev/docker-compose.full.yml down --volumes --remove-orphans
|
||||||
|
|
||||||
|
test: clean
|
||||||
|
go test -v -p=1 -ldflags="-X main.VERSION=dev" -coverprofile=coverage.out ./...
|
||||||
|
|
||||||
lite: clean
|
lite: clean
|
||||||
docker build -t hunterlong/statping:dev -f dev/Dockerfile.dev .
|
docker build -t hunterlong/statping:dev -f dev/Dockerfile.dev .
|
||||||
docker-compose -f dev/docker-compose.lite.yml down
|
docker-compose -f dev/docker-compose.lite.yml down
|
||||||
|
@ -107,7 +110,7 @@ clean:
|
||||||
rm -rf ./{logs,assets,plugins,*.db,config.yml,.sass-cache,config.yml,statping,build,.sass-cache,index.html,vendor}
|
rm -rf ./{logs,assets,plugins,*.db,config.yml,.sass-cache,config.yml,statping,build,.sass-cache,index.html,vendor}
|
||||||
rm -rf cmd/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log,*.html,*.json}
|
rm -rf cmd/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log,*.html,*.json}
|
||||||
rm -rf core/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log}
|
rm -rf core/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log}
|
||||||
rm -rf core/notifier/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log}
|
rm -rf types/notifications/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log}
|
||||||
rm -rf handlers/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log}
|
rm -rf handlers/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log}
|
||||||
rm -rf notifiers/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log}
|
rm -rf notifiers/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log}
|
||||||
rm -rf source/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log}
|
rm -rf source/{logs,assets,plugins,*.db,config.yml,.sass-cache,*.log}
|
||||||
|
|
|
@ -106,7 +106,7 @@ func catchCLI(args []string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = configs.ConnectConfigs(config, false); err != nil {
|
if err = configs.ConnectConfigs(config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if data, err = handlers.ExportSettings(); err != nil {
|
if data, err = handlers.ExportSettings(); err != nil {
|
||||||
|
@ -206,7 +206,7 @@ func runOnce() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "config.yml file not found")
|
return errors.Wrap(err, "config.yml file not found")
|
||||||
}
|
}
|
||||||
err = configs.ConnectConfigs(config, false)
|
err = configs.ConnectConfigs(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "issue connecting to database")
|
return errors.Wrap(err, "issue connecting to database")
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/hunterlong/statping/types/groups"
|
"github.com/hunterlong/statping/types/groups"
|
||||||
"github.com/hunterlong/statping/types/hits"
|
"github.com/hunterlong/statping/types/hits"
|
||||||
"github.com/hunterlong/statping/types/incidents"
|
"github.com/hunterlong/statping/types/incidents"
|
||||||
"github.com/hunterlong/statping/types/integrations"
|
|
||||||
"github.com/hunterlong/statping/types/messages"
|
"github.com/hunterlong/statping/types/messages"
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
"github.com/hunterlong/statping/types/notifications"
|
||||||
"github.com/hunterlong/statping/types/services"
|
"github.com/hunterlong/statping/types/services"
|
||||||
|
@ -19,5 +18,5 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}, &integrations.Integration{}}
|
DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||||
}
|
}
|
||||||
|
|
30
cmd/main.go
30
cmd/main.go
|
@ -19,6 +19,7 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/getsentry/sentry-go"
|
"github.com/getsentry/sentry-go"
|
||||||
|
"github.com/hunterlong/statping/notifiers"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
@ -125,14 +126,41 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = configs.ConnectConfigs(c, true); err != nil {
|
if err = configs.ConnectConfigs(c); err != nil {
|
||||||
exit(err)
|
exit(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exists := database.DB().HasTable("core")
|
||||||
|
if !exists {
|
||||||
|
|
||||||
|
if err := c.DropDatabase(); err != nil {
|
||||||
|
exit(errors.Wrap(err, "error dropping database"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := configs.CreateDatabase(); err != nil {
|
||||||
|
exit(errors.Wrap(err, "error creating database"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := configs.CreateAdminUser(c); err != nil {
|
||||||
|
exit(errors.Wrap(err, "error creating default admin user"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := configs.TriggerSamples(); err != nil {
|
||||||
|
exit(errors.Wrap(err, "error creating database"))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.MigrateDatabase(); err != nil {
|
if err := c.MigrateDatabase(); err != nil {
|
||||||
exit(err)
|
exit(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Infoln("Migrating Notifiers...")
|
||||||
|
if err := notifiers.Migrate(); err != nil {
|
||||||
|
exit(errors.Wrap(err, "error migrating notifiers"))
|
||||||
|
}
|
||||||
|
log.Infoln("Notifiers Migrated")
|
||||||
|
|
||||||
if err := mainProcess(); err != nil {
|
if err := mainProcess(); err != nil {
|
||||||
exit(err)
|
exit(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,19 +9,3 @@ type DbObject interface {
|
||||||
type Sampler interface {
|
type Sampler interface {
|
||||||
Sample() DbObject
|
Sample() DbObject
|
||||||
}
|
}
|
||||||
|
|
||||||
func MigrateTable(table interface{}) error {
|
|
||||||
tx := database.Begin()
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
tx.Rollback()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
tx = tx.AutoMigrate(table)
|
|
||||||
|
|
||||||
if err := tx.Commit().Error(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,171 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 database
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
_ "github.com/jinzhu/gorm/dialects/mysql"
|
|
||||||
_ "github.com/jinzhu/gorm/dialects/postgres"
|
|
||||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
sampleStart = time.Now().Add((-24 * 7) * time.Hour).UTC()
|
|
||||||
SampleHits = 9900.
|
|
||||||
)
|
|
||||||
|
|
||||||
// InsertSampleHits will create a couple new hits for the sample services
|
|
||||||
//func InsertSampleHits() error {
|
|
||||||
// tx := Begin(&hits.Hit{})
|
|
||||||
// sg := new(sync.WaitGroup)
|
|
||||||
// for i := int64(1); i <= 5; i++ {
|
|
||||||
// sg.Add(1)
|
|
||||||
// service := SelectService(i)
|
|
||||||
// seed := time.Now().UnixNano()
|
|
||||||
// log.Infoln(fmt.Sprintf("Adding %v sample hit records to service %v", SampleHits, service.Name))
|
|
||||||
// createdAt := sampleStart
|
|
||||||
// p := utils.NewPerlin(2., 2., 10, seed)
|
|
||||||
// go func(sg *sync.WaitGroup) {
|
|
||||||
// defer sg.Done()
|
|
||||||
// for hi := 0.; hi <= float64(SampleHits); hi++ {
|
|
||||||
// latency := p.Noise1D(hi / 500)
|
|
||||||
// createdAt = createdAt.Add(60 * time.Second)
|
|
||||||
// hit := &hits.Hit{
|
|
||||||
// Service: service.Id,
|
|
||||||
// CreatedAt: createdAt,
|
|
||||||
// Latency: latency,
|
|
||||||
// }
|
|
||||||
// tx = tx.Create(&hit)
|
|
||||||
// }
|
|
||||||
// }(sg)
|
|
||||||
// }
|
|
||||||
// sg.Wait()
|
|
||||||
// if err := tx.Commit().Error(); err != nil {
|
|
||||||
// log.Errorln(err)
|
|
||||||
// return types.ErrWrap(err, types.ErrorCreateSampleHits)
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
|
|
||||||
//func TmpRecords(dbFile string) error {
|
|
||||||
// var sqlFile = utils.Directory + "/" + dbFile
|
|
||||||
// if err := utils.CreateDirectory(utils.Directory + "/tmp"); err != nil {
|
|
||||||
// log.Error(err)
|
|
||||||
// }
|
|
||||||
// var tmpSqlFile = utils.Directory + "/tmp/" + dbFile
|
|
||||||
// SampleHits = 480
|
|
||||||
//
|
|
||||||
// var err error
|
|
||||||
// CoreApp = NewCore()
|
|
||||||
// CoreApp.Name = "Tester"
|
|
||||||
// CoreApp.Setup = true
|
|
||||||
// configs := &types.DbConfig{
|
|
||||||
// DbConn: "sqlite",
|
|
||||||
// Project: "Tester",
|
|
||||||
// Location: utils.Directory,
|
|
||||||
// SqlFile: sqlFile,
|
|
||||||
// }
|
|
||||||
// log.Infoln("saving config.yml in: " + utils.Directory)
|
|
||||||
// if err := configs.Save(utils.Directory); err != nil {
|
|
||||||
// log.Error(err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// log.Infoln("loading config.yml from: " + utils.Directory)
|
|
||||||
// if configs, err = LoadConfigs(); err != nil {
|
|
||||||
// log.Error(err)
|
|
||||||
// }
|
|
||||||
// log.Infoln("connecting to database")
|
|
||||||
//
|
|
||||||
// exists := utils.FileExists(tmpSqlFile)
|
|
||||||
// if exists {
|
|
||||||
// log.Infoln(tmpSqlFile + " was found, copying the temp database to " + sqlFile)
|
|
||||||
// if err := utils.DeleteFile(sqlFile); err != nil {
|
|
||||||
// log.Error(err)
|
|
||||||
// }
|
|
||||||
// if err := utils.CopyFile(tmpSqlFile, sqlFile); err != nil {
|
|
||||||
// log.Error(err)
|
|
||||||
// }
|
|
||||||
// log.Infoln("loading config.yml from: " + utils.Directory)
|
|
||||||
//
|
|
||||||
// if err := CoreApp.Connect(configs, false, utils.Directory); err != nil {
|
|
||||||
// log.Error(err)
|
|
||||||
// }
|
|
||||||
// log.Infoln("selecting the Core variable")
|
|
||||||
// if _, err := SelectCore(); err != nil {
|
|
||||||
// log.Error(err)
|
|
||||||
// }
|
|
||||||
// log.Infoln("inserting notifiers into database")
|
|
||||||
// if err := InsertNotifierDB(); err != nil {
|
|
||||||
// log.Error(err)
|
|
||||||
// }
|
|
||||||
// log.Infoln("inserting integrations into database")
|
|
||||||
// if err := InsertIntegratorDB(); err != nil {
|
|
||||||
// log.Error(err)
|
|
||||||
// }
|
|
||||||
// log.Infoln("loading all services")
|
|
||||||
// if _, err := SelectAllServices(false); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if err := AttachNotifiers(); err != nil {
|
|
||||||
// log.Error(err)
|
|
||||||
// }
|
|
||||||
// if err := AddIntegrations(); err != nil {
|
|
||||||
// log.Error(err)
|
|
||||||
// }
|
|
||||||
// CoreApp.Notifications = notifier.AllCommunications
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// log.Infoln(tmpSqlFile + " not found, creating a new database...")
|
|
||||||
//
|
|
||||||
// if err := CoreApp.Connect(configs, false, utils.Directory); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// log.Infoln("creating database")
|
|
||||||
// if err := CoreApp.CreateDatabase(); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// log.Infoln("migrating database")
|
|
||||||
// if err := MigrateDatabase(); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// log.Infoln("insert large sample data into database")
|
|
||||||
// if err := InsertLargeSampleData(); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// log.Infoln("selecting the Core variable")
|
|
||||||
// if CoreApp, err = SelectCore(); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// log.Infoln("inserting notifiers into database")
|
|
||||||
// if err := InsertNotifierDB(); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// log.Infoln("inserting integrations into database")
|
|
||||||
// if err := InsertIntegratorDB(); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// log.Infoln("loading all services")
|
|
||||||
// if _, err := SelectAllServices(false); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// log.Infoln("copying sql database file to: " + tmpSqlFile)
|
|
||||||
// if err := utils.CopyFile(sqlFile, tmpSqlFile); err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// return err
|
|
||||||
//}
|
|
|
@ -129,18 +129,6 @@ class Api {
|
||||||
return axios.post('/api/notifier/' + data.method + '/test', data).then(response => (response.data))
|
return axios.post('/api/notifier/' + data.method + '/test', data).then(response => (response.data))
|
||||||
}
|
}
|
||||||
|
|
||||||
async integrations() {
|
|
||||||
return axios.get('/api/integrations').then(response => (response.data))
|
|
||||||
}
|
|
||||||
|
|
||||||
async integration(name) {
|
|
||||||
return axios.get('/api/integrations/' + name).then(response => (response.data))
|
|
||||||
}
|
|
||||||
|
|
||||||
async integration_save(data) {
|
|
||||||
return axios.post('/api/integrations/' + data.name, data).then(response => (response.data))
|
|
||||||
}
|
|
||||||
|
|
||||||
async renewApiKeys() {
|
async renewApiKeys() {
|
||||||
return axios.get('/api/renew').then(response => (response.data))
|
return axios.get('/api/renew').then(response => (response.data))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card">
|
|
||||||
<div class="card-body">
|
|
||||||
<FormService :in_service="service"/>
|
<FormService :in_service="service"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -87,6 +87,37 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row d-none">
|
||||||
|
<div class="col-12">
|
||||||
|
<h4 class="mt-5">Github Authentication</h4>
|
||||||
|
|
||||||
|
<div class="form-group row d-none">
|
||||||
|
<label class="col-sm-4 col-form-label">Github Client ID</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input v-model="core.github_clientId" type="text" class="form-control" placeholder="" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-4 col-form-label">Github Client Secret</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input v-model="core.github_clientScret" type="text" class="form-control" placeholder="" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="switch-group-public" class="col-sm-4 col-form-label">Enabled</label>
|
||||||
|
<div class="col-md-8 col-xs-12 mt-1">
|
||||||
|
<span @click="enabled = !!enabled" class="switch float-left">
|
||||||
|
<input v-model="enabled" type="checkbox" class="switch" id="switch-group-public" :checked="enabled">
|
||||||
|
<label for="switch-group-public">Enabled Github Auth</label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button @click.prevent="saveSettings" type="submit" class="btn btn-primary btn-block">Save Settings</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -99,16 +130,14 @@
|
||||||
return {
|
return {
|
||||||
core: this.$store.getters.core,
|
core: this.$store.getters.core,
|
||||||
}
|
}
|
||||||
},
|
|
||||||
async mounted() {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
const c = this.core
|
const c = this.core
|
||||||
const coreForm = {
|
const coreForm = {
|
||||||
name: c.name, description: c.description, domain: c.domain,
|
name: c.name, description: c.description, domain: c.domain,
|
||||||
timezone: c.timezone, using_cdn: c.using_cdn, footer: c.footer, update_notify: c.update_notify
|
timezone: c.timezone, using_cdn: c.using_cdn, footer: c.footer, update_notify: c.update_notify,
|
||||||
|
gh_client_id: c.github_clientId, gh_client_secret: c.github_clientSecret
|
||||||
}
|
}
|
||||||
await Api.core_save(coreForm)
|
await Api.core_save(coreForm)
|
||||||
const core = await Api.core()
|
const core = await Api.core()
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
<template>
|
||||||
|
<form @submit="updateCore">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-4 col-form-label">Github Client ID</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input v-model="clientId" type="text" class="form-control" placeholder="" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-4 col-form-label">Github Client Secret</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<input v-model="clientSecret" type="text" class="form-control" placeholder="" required>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<label for="switch-group-public" class="col-sm-4 col-form-label">Enabled</label>
|
||||||
|
<div class="col-md-8 col-xs-12 mt-1">
|
||||||
|
<span @click="enabled = !!enabled" class="switch float-left">
|
||||||
|
<input v-model="enabled" type="checkbox" class="switch" id="switch-group-public" :checked="enabled">
|
||||||
|
<label for="switch-group-public">Enabled Github Auth</label>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<button @click="updateCore" type="submit" :disabled="loading || group.name === ''" class="btn btn-block" :class="{'btn-primary': !group.id, 'btn-secondary': group.id}">
|
||||||
|
{{loading ? "Loading..." : group.id ? "Update Group" : "Create Group"}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-danger d-none" id="alerter" role="alert"></div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Api from "../API";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'FormGroup',
|
||||||
|
props: {
|
||||||
|
in_group: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
type: Function
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
clientId: "",
|
||||||
|
clientSecret: "",
|
||||||
|
enabled: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
in_group() {
|
||||||
|
this.group = this.in_group
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
removeEdit() {
|
||||||
|
this.group = {}
|
||||||
|
this.edit(false)
|
||||||
|
},
|
||||||
|
async updateCore() {
|
||||||
|
const g = this.group
|
||||||
|
const data = {id: g.id, name: g.name, public: g.public}
|
||||||
|
await Api.core_save(data)
|
||||||
|
const groups = await Api.groups()
|
||||||
|
this.$store.commit('setGroups', groups)
|
||||||
|
this.edit(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
|
@ -22,6 +22,7 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -37,9 +38,13 @@
|
||||||
auth: {},
|
auth: {},
|
||||||
loading: false,
|
loading: false,
|
||||||
error: false,
|
error: false,
|
||||||
disabled: true
|
disabled: true,
|
||||||
|
ghLoginURL: ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.GHlogin()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
checkForm() {
|
checkForm() {
|
||||||
if (!this.username || !this.password) {
|
if (!this.username || !this.password) {
|
||||||
|
@ -60,6 +65,10 @@
|
||||||
this.$router.push('/dashboard')
|
this.$router.push('/dashboard')
|
||||||
}
|
}
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
},
|
||||||
|
async GHlogin() {
|
||||||
|
const core = this.$store.getters.core;
|
||||||
|
this.ghLoginURL = `https://github.com/login/oauth/authorize?client_id=${core.gh_client_id}&redirect_uri=${core.domain}/oauth/callback&scope=user,repo`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<form @submit.prevent="saveService">
|
<form @submit.prevent="saveService">
|
||||||
<h4 class="mb-5 text-muted">Basic Information</h4>
|
<div class="card contain-card text-black-50 bg-white mb-4">
|
||||||
|
<div class="card-header">Basic Information</div>
|
||||||
|
<div class="card-body">
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-4 col-form-label">Service Name</label>
|
<label class="col-sm-4 col-form-label">Service Name</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
|
@ -37,8 +39,12 @@
|
||||||
<small class="form-text text-muted">Attach this service to a group</small>
|
<small class="form-text text-muted">Attach this service to a group</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h4 v-if="service.type !== 'icmp'" class="mt-5 mb-5 text-muted">Request Details</h4>
|
<div v-if="service.type !== 'icmp'" class="card contain-card text-black-50 bg-white mb-4">
|
||||||
|
<div class="card-header">Request Details</div>
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
|
<div v-if="service.type.match(/^(http)$/)" class="form-group row">
|
||||||
<label class="col-sm-4 col-form-label">Service Check Type</label>
|
<label class="col-sm-4 col-form-label">Service Check Type</label>
|
||||||
|
@ -87,8 +93,12 @@
|
||||||
<input v-model="service.port" type="number" name="port" class="form-control" id="service_port" placeholder="8080">
|
<input v-model="service.port" type="number" name="port" class="form-control" id="service_port" placeholder="8080">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h4 class="mt-5 mb-5 text-muted">Additional Options</h4>
|
<div class="card contain-card text-black-50 bg-white mb-4">
|
||||||
|
<div class="card-header">Additional Options</div>
|
||||||
|
<div class="card-body">
|
||||||
|
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="service_interval" class="col-sm-4 col-form-label">Check Interval (Seconds)</label>
|
<label for="service_interval" class="col-sm-4 col-form-label">Check Interval (Seconds)</label>
|
||||||
|
@ -153,6 +163,8 @@
|
||||||
{{service.id ? "Update Service" : "Create Service"}}
|
{{service.id ? "Update Service" : "Create Service"}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="alert alert-danger d-none" id="alerter" role="alert"></div>
|
<div class="alert alert-danger d-none" id="alerter" role="alert"></div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -22,12 +22,6 @@
|
||||||
<span v-if="notifier.enabled" class="badge badge-pill float-right mt-1" :class="{'badge-success': !liClass(`v-pills-${notifier.method.toLowerCase()}-tab`), 'badge-light': liClass(`v-pills-${notifier.method.toLowerCase()}-tab`), 'text-dark': liClass(`v-pills-${notifier.method.toLowerCase()}-tab`)}">ON</span>
|
<span v-if="notifier.enabled" class="badge badge-pill float-right mt-1" :class="{'badge-success': !liClass(`v-pills-${notifier.method.toLowerCase()}-tab`), 'badge-light': liClass(`v-pills-${notifier.method.toLowerCase()}-tab`), 'text-dark': liClass(`v-pills-${notifier.method.toLowerCase()}-tab`)}">ON</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<h6 class="mt-4 text-muted">Integrations <span class="badge badge-secondary float-right">BETA</span></h6>
|
|
||||||
|
|
||||||
<a v-for="(integration, index) in $store.getters.integrations" v-bind:key="`${integration.name}_${index}`" @click.prevent="changeTab" class="nav-link text-capitalize" v-bind:class="{active: liClass(`v-pills-integration-${integration.name}`)}" v-bind:id="`v-pills-integration-${integration.name}`" data-toggle="pill" v-bind:href="`#v-pills-integration-${integration.name}`" role="tab" :aria-controls="`v-pills-integration-${integration.name}`" aria-selected="false">
|
|
||||||
<font-awesome-icon :icon="iconName(integration.name)" class="mr-2"/> {{integration.full_name}}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-9 col-sm-12">
|
<div class="col-md-9 col-sm-12">
|
||||||
|
@ -90,10 +84,6 @@
|
||||||
<Notifier :notifier="notifier"/>
|
<Notifier :notifier="notifier"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="(integration, index) in $store.getters.integrations" v-bind:key="`${integration.name}_${index}`" class="tab-pane fade" v-bind:class="{active: liClass(`v-pills-integration-${integration.name}`), show: liClass(`v-pills-integration-${integration.name}`)}" v-bind:id="`v-pills-integration-${integration.name}`" role="tabpanel">
|
|
||||||
<FormIntegration :integration="integration"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -33,6 +33,7 @@ require (
|
||||||
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e
|
github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e
|
||||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073
|
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073
|
||||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a // indirect
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect
|
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/mail.v2 v2.3.1 // indirect
|
gopkg.in/mail.v2 v2.3.1 // indirect
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,3 +1,4 @@
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
|
@ -300,6 +301,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
@ -310,6 +312,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
||||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/gorilla/mux"
|
|
||||||
"github.com/hunterlong/statping/types/integrations"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func findIntegration(r *http.Request) (*integrations.Integration, string, error) {
|
|
||||||
vars := mux.Vars(r)
|
|
||||||
name := vars["name"]
|
|
||||||
intgr, err := integrations.Find(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
return intgr, name, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func apiAllIntegrationsHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
inte := integrations.All()
|
|
||||||
returnJson(inte, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func apiIntegrationViewHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
intgr, _, err := findIntegration(r)
|
|
||||||
if err != nil {
|
|
||||||
sendErrorJson(err, w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
returnJson(intgr, w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func apiIntegrationHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
intgr, _, err := findIntegration(r)
|
|
||||||
if err != nil {
|
|
||||||
sendErrorJson(err, w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
if err := decoder.Decode(&intgr); err != nil {
|
|
||||||
sendErrorJson(err, w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := intgr.Update(); err != nil {
|
|
||||||
sendErrorJson(err, w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
returnJson(intgr, w, r)
|
|
||||||
}
|
|
|
@ -27,12 +27,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) {
|
func apiNotifiersHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var notifiers []*notifications.Notification
|
all := notifications.All()
|
||||||
for _, n := range core.App.Notifications {
|
returnJson(all, w, r)
|
||||||
notif := n.(notifications.Notifier)
|
|
||||||
notifiers = append(notifiers, notif.Select())
|
|
||||||
}
|
|
||||||
returnJson(notifiers, w, r)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
|
func apiNotifierGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -104,7 +104,8 @@ func prometheusHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, notif := range notifications.All() {
|
for _, n := range notifications.All() {
|
||||||
|
notif := n.Select()
|
||||||
PrometheusComment(fmt.Sprintf("Notifier %s:", notif.Method))
|
PrometheusComment(fmt.Sprintf("Notifier %s:", notif.Method))
|
||||||
enabled := 0
|
enabled := 0
|
||||||
if notif.Enabled.Bool {
|
if notif.Enabled.Bool {
|
||||||
|
|
|
@ -87,6 +87,7 @@ func Router() *mux.Router {
|
||||||
|
|
||||||
// API Routes
|
// API Routes
|
||||||
r.Handle("/api", scoped(apiIndexHandler))
|
r.Handle("/api", scoped(apiIndexHandler))
|
||||||
|
//r.Handle("/oauth/callback", http.HandlerFunc(OAuthRedirect))
|
||||||
api.Handle("/api/login", http.HandlerFunc(apiLoginHandler)).Methods("POST")
|
api.Handle("/api/login", http.HandlerFunc(apiLoginHandler)).Methods("POST")
|
||||||
r.Handle("/api/setup", http.HandlerFunc(processSetupHandler)).Methods("POST")
|
r.Handle("/api/setup", http.HandlerFunc(processSetupHandler)).Methods("POST")
|
||||||
api.Handle("/api/logout", http.HandlerFunc(logoutHandler))
|
api.Handle("/api/logout", http.HandlerFunc(logoutHandler))
|
||||||
|
@ -103,11 +104,6 @@ func Router() *mux.Router {
|
||||||
api.Handle("/api/theme/create", authenticated(apiThemeCreateHandler, false)).Methods("GET")
|
api.Handle("/api/theme/create", authenticated(apiThemeCreateHandler, false)).Methods("GET")
|
||||||
api.Handle("/api/theme", authenticated(apiThemeRemoveHandler, false)).Methods("DELETE")
|
api.Handle("/api/theme", authenticated(apiThemeRemoveHandler, false)).Methods("DELETE")
|
||||||
|
|
||||||
// API INTEGRATIONS Routes
|
|
||||||
api.Handle("/api/integrations", authenticated(apiAllIntegrationsHandler, false)).Methods("GET")
|
|
||||||
api.Handle("/api/integrations/{name}", authenticated(apiIntegrationViewHandler, false)).Methods("GET")
|
|
||||||
api.Handle("/api/integrations/{name}", authenticated(apiIntegrationHandler, false)).Methods("POST")
|
|
||||||
|
|
||||||
// API GROUPS Routes
|
// API GROUPS Routes
|
||||||
api.Handle("/api/groups", scoped(apiAllGroupHandler)).Methods("GET")
|
api.Handle("/api/groups", scoped(apiAllGroupHandler)).Methods("GET")
|
||||||
api.Handle("/api/groups", authenticated(apiCreateGroupHandler, false)).Methods("POST")
|
api.Handle("/api/groups", authenticated(apiCreateGroupHandler, false)).Methods("POST")
|
||||||
|
|
|
@ -81,6 +81,7 @@ func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(err, w, r)
|
sendErrorJson(err, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
go services.ServiceCheckQueue(service, true)
|
||||||
|
|
||||||
sendJsonAction(service, "create", w, r)
|
sendJsonAction(service, "create", w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/hunterlong/statping/database"
|
||||||
|
"github.com/hunterlong/statping/notifiers"
|
||||||
"github.com/hunterlong/statping/types/configs"
|
"github.com/hunterlong/statping/types/configs"
|
||||||
"github.com/hunterlong/statping/types/core"
|
"github.com/hunterlong/statping/types/core"
|
||||||
"github.com/hunterlong/statping/types/null"
|
"github.com/hunterlong/statping/types/null"
|
||||||
|
@ -43,7 +45,7 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
log.WithFields(utils.ToFields(core.App, confgs)).Debugln("new configs posted")
|
log.WithFields(utils.ToFields(core.App, confgs)).Debugln("new configs posted")
|
||||||
|
|
||||||
if err = configs.ConnectConfigs(confgs, true); err != nil {
|
if err = configs.ConnectConfigs(confgs); err != nil {
|
||||||
log.Errorln(err)
|
log.Errorln(err)
|
||||||
if err := confgs.Delete(); err != nil {
|
if err := confgs.Delete(); err != nil {
|
||||||
log.Errorln(err)
|
log.Errorln(err)
|
||||||
|
@ -60,11 +62,40 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exists := database.DB().HasTable("core")
|
||||||
|
if !exists {
|
||||||
|
if err := confgs.DropDatabase(); err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := configs.CreateDatabase(); err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := configs.CreateAdminUser(confgs); err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := configs.TriggerSamples(); err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err = confgs.MigrateDatabase(); err != nil {
|
if err = confgs.MigrateDatabase(); err != nil {
|
||||||
sendErrorJson(err, w, r)
|
sendErrorJson(err, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Infoln("Migrating Notifiers...")
|
||||||
|
if err := notifiers.Migrate(); err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c := &core.Core{
|
c := &core.Core{
|
||||||
Name: "Statping Sample Data",
|
Name: "Statping Sample Data",
|
||||||
Description: "This data is only used to testing",
|
Description: "This data is only used to testing",
|
||||||
|
@ -86,15 +117,6 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
core.App = c
|
core.App = c
|
||||||
|
|
||||||
//if sample {
|
|
||||||
// log.Infoln("Adding sample data into new database")
|
|
||||||
// if err = configs.TriggerSamples(); err != nil {
|
|
||||||
// log.Errorln(err)
|
|
||||||
// sendErrorJson(err, w, r)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
log.Infoln("Initializing new Statping instance")
|
log.Infoln("Initializing new Statping instance")
|
||||||
if err := core.InitApp(); err != nil {
|
if err := core.InitApp(); err != nil {
|
||||||
log.Errorln(err)
|
log.Errorln(err)
|
||||||
|
|
|
@ -1,132 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 integrators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/csv"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/hunterlong/statping/types/integrations"
|
|
||||||
"github.com/hunterlong/statping/types/null"
|
|
||||||
"github.com/hunterlong/statping/types/services"
|
|
||||||
"github.com/hunterlong/statping/utils"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const requiredSize = 17
|
|
||||||
|
|
||||||
type csvIntegration struct {
|
|
||||||
*integrations.Integration
|
|
||||||
}
|
|
||||||
|
|
||||||
var CsvIntegrator = &csvIntegration{&integrations.Integration{
|
|
||||||
ShortName: "csv",
|
|
||||||
Name: "CSV File",
|
|
||||||
Icon: "<i class=\"fas fa-file-csv\"></i>",
|
|
||||||
Description: "Import multiple services from a CSV file. Please have your CSV file formatted with the correct amount of columns based on the <a href=\"https://raw.githubusercontent.com/hunterlong/statping/master/source/tmpl/bulk_import.csv\">example file on Github</a>.",
|
|
||||||
Fields: []*integrations.IntegrationField{
|
|
||||||
{
|
|
||||||
Name: "input",
|
|
||||||
Type: "textarea",
|
|
||||||
Description: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
|
|
||||||
var csvData [][]string
|
|
||||||
|
|
||||||
func (t *csvIntegration) Get() *integrations.Integration {
|
|
||||||
return t.Integration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *csvIntegration) List() ([]*services.Service, error) {
|
|
||||||
data := Value(t, "input").(string)
|
|
||||||
buf := bytes.NewReader([]byte(data))
|
|
||||||
r := csv.NewReader(buf)
|
|
||||||
records, err := r.ReadAll()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var services []*services.Service
|
|
||||||
for k, v := range records[1:] {
|
|
||||||
s, err := commaToService(v)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("error on line %v: %v", k, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
services = append(services, s)
|
|
||||||
}
|
|
||||||
return services, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// commaToService will convert a CSV comma delimited string slice to a Service type
|
|
||||||
// this function is used for the bulk import services feature
|
|
||||||
func commaToService(s []string) (*services.Service, error) {
|
|
||||||
if len(s) != requiredSize {
|
|
||||||
err := fmt.Errorf("file has %v columns of data, not the expected amount of %v columns for a service", len(s), requiredSize)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
interval, err := time.ParseDuration(s[4])
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("could not parse internal duration: " + s[4])
|
|
||||||
}
|
|
||||||
|
|
||||||
timeout, err := time.ParseDuration(s[9])
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("could not parse timeout duration: " + s[9])
|
|
||||||
}
|
|
||||||
|
|
||||||
allowNotifications, err := strconv.ParseBool(s[11])
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("could not parse allow notifications boolean: " + s[11])
|
|
||||||
}
|
|
||||||
|
|
||||||
public, err := strconv.ParseBool(s[12])
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("could not parse public boolean: " + s[12])
|
|
||||||
}
|
|
||||||
|
|
||||||
verifySsl, err := strconv.ParseBool(s[16])
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("could not parse verifiy SSL boolean: " + s[16])
|
|
||||||
}
|
|
||||||
|
|
||||||
newService := &services.Service{
|
|
||||||
Name: s[0],
|
|
||||||
Domain: s[1],
|
|
||||||
Expected: null.NewNullString(s[2]),
|
|
||||||
ExpectedStatus: int(utils.ToInt(s[3])),
|
|
||||||
Interval: int(utils.ToInt(interval.Seconds())),
|
|
||||||
Type: s[5],
|
|
||||||
Method: s[6],
|
|
||||||
PostData: null.NewNullString(s[7]),
|
|
||||||
Port: int(utils.ToInt(s[8])),
|
|
||||||
Timeout: int(utils.ToInt(timeout.Seconds())),
|
|
||||||
AllowNotifications: null.NewNullBool(allowNotifications),
|
|
||||||
Public: null.NewNullBool(public),
|
|
||||||
GroupId: int(utils.ToInt(s[13])),
|
|
||||||
Headers: null.NewNullString(s[14]),
|
|
||||||
Permalink: null.NewNullString(s[15]),
|
|
||||||
VerifySSL: null.NewNullBool(verifySsl),
|
|
||||||
}
|
|
||||||
|
|
||||||
return newService, nil
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package integrators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"io/ioutil"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCsvFileIntegration(t *testing.T) {
|
|
||||||
data, err := ioutil.ReadFile("testdata/bulk_import.csv")
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
t.Run("Set Field Value", func(t *testing.T) {
|
|
||||||
formPost := map[string][]string{}
|
|
||||||
formPost["input"] = []string{string(data)}
|
|
||||||
_, err = SetFields(CsvIntegrator, formPost)
|
|
||||||
require.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Get Field Value", func(t *testing.T) {
|
|
||||||
value := Value(CsvIntegrator, "input").(string)
|
|
||||||
assert.Equal(t, string(data), value)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("List Services from CSV File", func(t *testing.T) {
|
|
||||||
services, err := CsvIntegrator.List()
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, 10, len(services))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Confirm Services from CSV File", func(t *testing.T) {
|
|
||||||
services, err := CsvIntegrator.List()
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, "Bulk Upload", services[0].Name)
|
|
||||||
assert.Equal(t, "http://google.com", services[0].Domain)
|
|
||||||
assert.Equal(t, 60, services[0].Interval)
|
|
||||||
for _, s := range services {
|
|
||||||
t.Log(s)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 integrators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
dTypes "github.com/docker/docker/api/types"
|
|
||||||
"github.com/docker/docker/client"
|
|
||||||
"github.com/hunterlong/statping/types/integrations"
|
|
||||||
"github.com/hunterlong/statping/types/services"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
type dockerIntegration struct {
|
|
||||||
*integrations.Integration
|
|
||||||
}
|
|
||||||
|
|
||||||
var DockerIntegrator = &dockerIntegration{&integrations.Integration{
|
|
||||||
ShortName: "docker",
|
|
||||||
Name: "Docker",
|
|
||||||
Icon: "<i class=\"fab fa-docker\"></i>",
|
|
||||||
Description: `Import multiple services from Docker by attaching the unix socket to Statping.
|
|
||||||
You can also do this in Docker by setting <u>-v /var/run/docker.sock:/var/run/docker.sock</u> in the Statping Docker container.
|
|
||||||
All of the containers with open TCP/UDP ports will be listed for you to choose which services you want to add. If you running Statping inside of a container,
|
|
||||||
this container must be attached to all networks you want to communicate with.`,
|
|
||||||
Fields: []*integrations.IntegrationField{
|
|
||||||
{
|
|
||||||
Name: "path",
|
|
||||||
Description: "The absolute path to the Docker unix socket",
|
|
||||||
Type: "text",
|
|
||||||
Value: client.DefaultDockerHost,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "version",
|
|
||||||
Description: "Version number of Docker server",
|
|
||||||
Type: "text",
|
|
||||||
Value: client.DefaultVersion,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
|
|
||||||
var cli *client.Client
|
|
||||||
|
|
||||||
func (t *dockerIntegration) Get() *integrations.Integration {
|
|
||||||
return t.Integration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *dockerIntegration) List() ([]*services.Service, error) {
|
|
||||||
var err error
|
|
||||||
path := Value(t, "path").(string)
|
|
||||||
version := Value(t, "version").(string)
|
|
||||||
os.Setenv("DOCKER_HOST", path)
|
|
||||||
os.Setenv("DOCKER_VERSION", version)
|
|
||||||
cli, err = client.NewEnvClient()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer cli.Close()
|
|
||||||
|
|
||||||
var srvs []*services.Service
|
|
||||||
|
|
||||||
containers, err := cli.ContainerList(context.Background(), dTypes.ContainerListOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, container := range containers {
|
|
||||||
if container.State != "running" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range container.Ports {
|
|
||||||
if v.IP == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
service := &services.Service{
|
|
||||||
Name: container.Names[0][1:],
|
|
||||||
Domain: v.IP,
|
|
||||||
Type: v.Type,
|
|
||||||
Port: int(v.PublicPort),
|
|
||||||
Interval: 60,
|
|
||||||
Timeout: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
srvs = append(srvs, service)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return srvs, nil
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
package integrators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDockerIntegration(t *testing.T) {
|
|
||||||
|
|
||||||
t.SkipNow()
|
|
||||||
|
|
||||||
t.Run("Set Field Value", func(t *testing.T) {
|
|
||||||
formPost := map[string][]string{}
|
|
||||||
formPost["path"] = []string{"unix:///var/run/docker.sock"}
|
|
||||||
formPost["version"] = []string{"1.25"}
|
|
||||||
_, err := SetFields(CsvIntegrator, formPost)
|
|
||||||
require.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Get Field Value", func(t *testing.T) {
|
|
||||||
path := Value(DockerIntegrator, "path").(string)
|
|
||||||
version := Value(DockerIntegrator, "version").(string)
|
|
||||||
assert.Equal(t, "unix:///var/run/docker.sock", path)
|
|
||||||
assert.Equal(t, "1.25", version)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("List Services from Docker", func(t *testing.T) {
|
|
||||||
services, err := DockerIntegrator.List()
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, 0, len(services))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Confirm Services from Docker", func(t *testing.T) {
|
|
||||||
services, err := DockerIntegrator.List()
|
|
||||||
require.Nil(t, err)
|
|
||||||
for _, s := range services {
|
|
||||||
t.Log(s)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,169 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 integrators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/hunterlong/statping/database"
|
|
||||||
"github.com/hunterlong/statping/types/integrations"
|
|
||||||
"github.com/hunterlong/statping/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
Integrations []integrations.Integrator
|
|
||||||
log = utils.Log.WithField("type", "integration")
|
|
||||||
db database.Database
|
|
||||||
)
|
|
||||||
|
|
||||||
//func init() {
|
|
||||||
// Integrations = append(Integrations,
|
|
||||||
// CsvIntegrator,
|
|
||||||
// DockerIntegrator,
|
|
||||||
// TraefikIntegrator,
|
|
||||||
// )
|
|
||||||
//}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
AddIntegrations(
|
|
||||||
CsvIntegrator,
|
|
||||||
TraefikIntegrator,
|
|
||||||
DockerIntegrator,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// integrationsDb returns the 'integrations' database column
|
|
||||||
func integrationsDb() database.Database {
|
|
||||||
return db.Model(&integrations.Integration{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDB is called by core to inject the database for a integrator to use
|
|
||||||
func SetDB(d database.Database) {
|
|
||||||
db = d
|
|
||||||
}
|
|
||||||
|
|
||||||
func Value(intg integrations.Integrator, fieldName string) interface{} {
|
|
||||||
for _, v := range intg.Get().Fields {
|
|
||||||
if fieldName == v.Name {
|
|
||||||
return v.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Update(integrator *integrations.Integration) error {
|
|
||||||
fields := FieldsToJson(integrator)
|
|
||||||
fmt.Println(fields)
|
|
||||||
set := db.Model(&integrations.Integration{}).Where("name = ?", integrator.Name)
|
|
||||||
set.Set("enabled", integrator.Enabled)
|
|
||||||
set.Set("fields", fields)
|
|
||||||
return set.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func FieldsToJson(integrator *integrations.Integration) string {
|
|
||||||
jsonData := make(map[string]interface{})
|
|
||||||
for _, v := range integrator.Fields {
|
|
||||||
jsonData[v.Name] = v.Value
|
|
||||||
}
|
|
||||||
data, _ := json.Marshal(jsonData)
|
|
||||||
return string(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func JsonToFields(intg integrations.Integrator, input string) []*integrations.IntegrationField {
|
|
||||||
integrator := intg.Get()
|
|
||||||
var jsonData map[string]interface{}
|
|
||||||
json.Unmarshal([]byte(input), &jsonData)
|
|
||||||
|
|
||||||
for _, v := range integrator.Fields {
|
|
||||||
v.Value = jsonData[v.Name]
|
|
||||||
}
|
|
||||||
return integrator.Fields
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetFields(intg integrations.Integrator, data map[string][]string) (*integrations.Integration, error) {
|
|
||||||
i := intg.Get()
|
|
||||||
for _, v := range i.Fields {
|
|
||||||
if data[v.Name] != nil {
|
|
||||||
v.Value = data[v.Name][0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Find(name string) (integrations.Integrator, error) {
|
|
||||||
for _, i := range Integrations {
|
|
||||||
obj := i.Get()
|
|
||||||
if obj.ShortName == name {
|
|
||||||
return i, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, errors.New(name + " not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// db will return the notifier database column/record
|
|
||||||
func integratorDb(n *integrations.Integration) database.Database {
|
|
||||||
return db.Model(&integrations.Integration{}).Where("name = ?", n.Name).Find(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// isInDatabase returns true if the integration has already been installed
|
|
||||||
func isInDatabase(i integrations.Integrator) bool {
|
|
||||||
inDb := integratorDb(i.Get()).RecordNotFound()
|
|
||||||
return !inDb
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectIntegration returns the Notification struct from the database
|
|
||||||
func SelectIntegration(i integrations.Integrator) (*integrations.Integration, error) {
|
|
||||||
integration := i.Get()
|
|
||||||
err := db.Model(&integrations.Integration{}).Where("name = ?", integration.Name).Scan(&integration)
|
|
||||||
return integration, err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddIntegrations accept a Integrator interface to be added into the array
|
|
||||||
func AddIntegrations(inte ...integrations.Integrator) error {
|
|
||||||
for _, i := range inte {
|
|
||||||
if utils.IsType(i, new(integrations.Integrator)) {
|
|
||||||
Integrations = append(Integrations, i)
|
|
||||||
err := install(i)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return errors.New("notifier does not have the required methods")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// install will check the database for the notification, if its not inserted it will insert a new record for it
|
|
||||||
func install(i integrations.Integrator) error {
|
|
||||||
_, err := insertDatabase(i)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorln(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// insertDatabase will create a new record into the database for the integrator
|
|
||||||
func insertDatabase(i integrations.Integrator) (string, error) {
|
|
||||||
integrator := i.Get()
|
|
||||||
query := db.FirstOrCreate(integrator)
|
|
||||||
if query.Error() != nil {
|
|
||||||
return "", query.Error()
|
|
||||||
}
|
|
||||||
return integrator.Name, query.Error()
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
name,domain,expected,expected_status,interval,type,method,post_data,port,timeout,order,allow_notifications,public,group_id,headers,permalink,verify_ssl
|
|
||||||
Bulk Upload,http://google.com,,200,60s,http,get,,,60s,1,TRUE,TRUE,,Authorization=example,bulk_example,FALSE
|
|
||||||
JSON Post,https://jsonplaceholder.typicode.com/posts,,200,1m,http,post,"{""id"": 1, ""title"": 'foo', ""body"": 'bar', ""userId"": 1}",,15s,2,TRUE,TRUE,,Content-Type=application/json,json_post_example,FALSE
|
|
||||||
Google DNS,8.8.8.8,,,60s,tcp,,,53,10s,3,TRUE,TRUE,,,google_dns_example,FALSE
|
|
||||||
Google DNS UDP,8.8.8.8,,,60s,udp,,,53,10s,4,TRUE,TRUE,,,google_dns_udp_example,FALSE
|
|
||||||
Statping Demo Page,https://demo.statping.com/health,"(\""online\"": true)",200,30s,http,get,,,10s,5,TRUE,TRUE,,,demo_link,FALSE
|
|
||||||
Statping MySQL Page,https://mysql.statping.com/health,"(\""online\"": true)",200,30s,http,get,,,10s,6,TRUE,TRUE,,,mysql_demo_link,FALSE
|
|
||||||
Statping SQLite Page,https://sqlite.statping.com/health,"(\""online\"": true)",200,30s,http,get,,,10s,7,TRUE,TRUE,,,sqlite_demo_link,FALSE
|
|
||||||
Token Balance,https://status.tokenbalance.com/health,"(\""online\"": true)",200,30s,http,get,,,10s,8,TRUE,TRUE,,,token_balance,FALSE
|
|
||||||
CloudFlare DNS,1.1.1.1,,,60s,tcp,,,53,10s,9,TRUE,TRUE,,,cloudflare_dns_example,FALSE
|
|
||||||
Verisign DNS,64.6.64.4,,,60s,tcp,,,53,10s,10,TRUE,TRUE,,,verisign_dns_example,FALSE
|
|
|
|
@ -1,127 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 integrators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"github.com/hunterlong/statping/types/integrations"
|
|
||||||
"github.com/hunterlong/statping/types/services"
|
|
||||||
"github.com/hunterlong/statping/utils"
|
|
||||||
"net/url"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type traefikIntegration struct {
|
|
||||||
*integrations.Integration
|
|
||||||
}
|
|
||||||
|
|
||||||
var TraefikIntegrator = &traefikIntegration{&integrations.Integration{
|
|
||||||
ShortName: "traefik",
|
|
||||||
Name: "Traefik",
|
|
||||||
Icon: "<i class=\"fas fa-network-wired\"></i>",
|
|
||||||
Description: ``,
|
|
||||||
Fields: []*integrations.IntegrationField{
|
|
||||||
{
|
|
||||||
Name: "endpoint",
|
|
||||||
Description: "The URL for the traefik API Endpoint",
|
|
||||||
Type: "text",
|
|
||||||
Value: "http://localhost:8080",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "username",
|
|
||||||
Description: "Username for HTTP Basic Authentication",
|
|
||||||
Type: "text",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "password",
|
|
||||||
Description: "Password for HTTP Basic Authentication",
|
|
||||||
Type: "password",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
|
|
||||||
func (t *traefikIntegration) Get() *integrations.Integration {
|
|
||||||
return t.Integration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *traefikIntegration) List() ([]*services.Service, error) {
|
|
||||||
var err error
|
|
||||||
var services []*services.Service
|
|
||||||
|
|
||||||
endpoint := Value(t, "endpoint").(string)
|
|
||||||
|
|
||||||
httpServices, err := fetchMethod(endpoint, "http")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
services = append(services, httpServices...)
|
|
||||||
|
|
||||||
tcpServices, err := fetchMethod(endpoint, "tcp")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
services = append(services, tcpServices...)
|
|
||||||
|
|
||||||
return services, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchMethod(endpoint, method string) ([]*services.Service, error) {
|
|
||||||
var traefikServices []traefikService
|
|
||||||
var srvs []*services.Service
|
|
||||||
d, _, err := utils.HttpRequest(endpoint+"/api/"+method+"/services", "GET", nil, []string{}, nil, 10*time.Second, false)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(d, &traefikServices); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, s := range traefikServices {
|
|
||||||
log.Infoln(s)
|
|
||||||
|
|
||||||
for _, l := range s.LoadBalancer.Servers {
|
|
||||||
|
|
||||||
url, err := url.Parse(l.URL)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
service := &services.Service{
|
|
||||||
Name: s.Name,
|
|
||||||
Domain: url.Hostname(),
|
|
||||||
Port: int(utils.ToInt(url.Port())),
|
|
||||||
Type: method,
|
|
||||||
Interval: 60,
|
|
||||||
Timeout: 2,
|
|
||||||
}
|
|
||||||
srvs = append(srvs, service)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return srvs, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type traefikService struct {
|
|
||||||
Status string `json:"status"`
|
|
||||||
UsedBy []string `json:"usedBy"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Provider string `json:"provider"`
|
|
||||||
LoadBalancer struct {
|
|
||||||
Servers []struct {
|
|
||||||
URL string `json:"url"`
|
|
||||||
} `json:"servers"`
|
|
||||||
PassHostHeader bool `json:"passHostHeader"`
|
|
||||||
} `json:"loadBalancer,omitempty"`
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package integrators
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTraefikIntegration(t *testing.T) {
|
|
||||||
|
|
||||||
t.SkipNow()
|
|
||||||
|
|
||||||
t.Run("List Services from Traefik", func(t *testing.T) {
|
|
||||||
services, err := TraefikIntegrator.List()
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.NotEqual(t, 0, len(services))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Confirm Services from Traefik", func(t *testing.T) {
|
|
||||||
services, err := TraefikIntegrator.List()
|
|
||||||
require.Nil(t, err)
|
|
||||||
for _, s := range services {
|
|
||||||
t.Log(s)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -25,12 +25,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ notifications.Notifier = (*commandLine)(nil)
|
||||||
|
|
||||||
type commandLine struct {
|
type commandLine struct {
|
||||||
*notifications.Notification
|
*notifications.Notification
|
||||||
}
|
}
|
||||||
|
|
||||||
var Command = &commandLine{¬ifications.Notification{
|
var Command = &commandLine{¬ifications.Notification{
|
||||||
Method: "Command",
|
Method: "command",
|
||||||
Title: "Shell Command",
|
Title: "Shell Command",
|
||||||
Description: "Shell Command allows you to run a customized shell/bash Command on the local machine it's running on.",
|
Description: "Shell Command allows you to run a customized shell/bash Command on the local machine it's running on.",
|
||||||
Author: "Hunter Long",
|
Author: "Hunter Long",
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
commandTest = "curl -I https://statping.com/"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCommandNotifier(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
Command.Host = "sh"
|
|
||||||
Command.Var1 = commandTest
|
|
||||||
Command.Var2 = commandTest
|
|
||||||
currentCount = CountNotifiers()
|
|
||||||
|
|
||||||
t.Run("Load Command", func(t *testing.T) {
|
|
||||||
Command.Host = "sh"
|
|
||||||
Command.Var1 = commandTest
|
|
||||||
Command.Var2 = commandTest
|
|
||||||
Command.Delay = time.Duration(100 * time.Millisecond)
|
|
||||||
Command.Limits = 99
|
|
||||||
err := AddNotifiers(Command)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "Hunter Long", Command.Author)
|
|
||||||
assert.Equal(t, "sh", Command.Host)
|
|
||||||
assert.Equal(t, commandTest, Command.Var1)
|
|
||||||
assert.Equal(t, commandTest, Command.Var2)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Command Notifier Tester", func(t *testing.T) {
|
|
||||||
assert.True(t, Command.CanTest())
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Command Within Limits", func(t *testing.T) {
|
|
||||||
ok, err := Command.WithinLimits()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Command OnFailure", func(t *testing.T) {
|
|
||||||
Command.OnFailure(TestService, TestFailure)
|
|
||||||
assert.Equal(t, 1, len(Command.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Command OnSuccess", func(t *testing.T) {
|
|
||||||
Command.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Command.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Command OnSuccess Again", func(t *testing.T) {
|
|
||||||
Command.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Command.Queue))
|
|
||||||
go notifications.Queue(Command)
|
|
||||||
time.Sleep(20 * time.Second)
|
|
||||||
assert.Equal(t, 0, len(Command.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Command Within Limits again", func(t *testing.T) {
|
|
||||||
ok, err := Command.WithinLimits()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Command Send", func(t *testing.T) {
|
|
||||||
Command.Send(commandTest)
|
|
||||||
assert.Equal(t, 0, len(Command.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Command Test", func(t *testing.T) {
|
|
||||||
Command.OnTest()
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Command Queue", func(t *testing.T) {
|
|
||||||
go notifications.Queue(Command)
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
assert.Equal(t, "sh", Command.Host)
|
|
||||||
assert.Equal(t, commandTest, Command.Var1)
|
|
||||||
assert.Equal(t, commandTest, Command.Var2)
|
|
||||||
assert.Equal(t, 0, len(Command.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -28,6 +28,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ notifications.Notifier = (*discord)(nil)
|
||||||
|
|
||||||
type discord struct {
|
type discord struct {
|
||||||
*notifications.Notification
|
*notifications.Notification
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,99 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
DISCORD_URL = os.Getenv("DISCORD_URL")
|
|
||||||
discordMessage = `{"content": "The discord notifier on Statping has been tested!"}`
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
DISCORD_URL = os.Getenv("DISCORD_URL")
|
|
||||||
Discorder.Host = DISCORD_URL
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDiscordNotifier(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
if DISCORD_URL == "" {
|
|
||||||
t.Log("discord notifier testing skipped, missing DISCORD_URL environment variable")
|
|
||||||
t.SkipNow()
|
|
||||||
}
|
|
||||||
currentCount = CountNotifiers()
|
|
||||||
|
|
||||||
t.Run("Load discord", func(t *testing.T) {
|
|
||||||
Discorder.Host = DISCORD_URL
|
|
||||||
Discorder.Delay = time.Duration(100 * time.Millisecond)
|
|
||||||
err := AddNotifiers(Discorder)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "Hunter Long", Discorder.Author)
|
|
||||||
assert.Equal(t, DISCORD_URL, Discorder.Host)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("discord Notifier Tester", func(t *testing.T) {
|
|
||||||
assert.True(t, Discorder.CanTest())
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("discord Within Limits", func(t *testing.T) {
|
|
||||||
ok, err := Discorder.WithinLimits()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("discord OnFailure", func(t *testing.T) {
|
|
||||||
Discorder.OnFailure(TestService, TestFailure)
|
|
||||||
assert.Equal(t, 1, len(Discorder.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("discord OnSuccess", func(t *testing.T) {
|
|
||||||
Discorder.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Discorder.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("discord Check Back Online", func(t *testing.T) {
|
|
||||||
assert.True(t, TestService.Online)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("discord OnSuccess Again", func(t *testing.T) {
|
|
||||||
Discorder.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Discorder.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("discord Send", func(t *testing.T) {
|
|
||||||
err := Discorder.Send(discordMessage)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("discord Test", func(t *testing.T) {
|
|
||||||
err := Discorder.OnTest()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("discord Queue", func(t *testing.T) {
|
|
||||||
go notifications.Queue(Discorder)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
assert.Equal(t, DISCORD_URL, Discorder.Host)
|
|
||||||
assert.Equal(t, 0, len(Discorder.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -29,6 +29,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ notifications.Notifier = (*email)(nil)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
mainEmailTemplate = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
mainEmailTemplate = `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
|
|
@ -1,136 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"fmt"
|
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
|
||||||
"github.com/hunterlong/statping/utils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
EMAIL_HOST string
|
|
||||||
EMAIL_USER string
|
|
||||||
EMAIL_PASS string
|
|
||||||
EMAIL_OUTGOING string
|
|
||||||
EMAIL_SEND_TO string
|
|
||||||
EMAIL_PORT int64
|
|
||||||
)
|
|
||||||
|
|
||||||
var testEmail *emailOutgoing
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
EMAIL_HOST = os.Getenv("EMAIL_HOST")
|
|
||||||
EMAIL_USER = os.Getenv("EMAIL_USER")
|
|
||||||
EMAIL_PASS = os.Getenv("EMAIL_PASS")
|
|
||||||
EMAIL_OUTGOING = os.Getenv("EMAIL_OUTGOING")
|
|
||||||
EMAIL_SEND_TO = os.Getenv("EMAIL_SEND_TO")
|
|
||||||
EMAIL_PORT = utils.ToInt(os.Getenv("EMAIL_PORT"))
|
|
||||||
|
|
||||||
Emailer.Host = EMAIL_HOST
|
|
||||||
Emailer.Username = EMAIL_USER
|
|
||||||
Emailer.Password = EMAIL_PASS
|
|
||||||
Emailer.Var1 = EMAIL_OUTGOING
|
|
||||||
Emailer.Var2 = EMAIL_SEND_TO
|
|
||||||
Emailer.Port = int(EMAIL_PORT)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEmailNotifier(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
if EMAIL_HOST == "" || EMAIL_USER == "" || EMAIL_PASS == "" {
|
|
||||||
t.Log("email notifier testing skipped, missing EMAIL_ environment variables")
|
|
||||||
t.SkipNow()
|
|
||||||
}
|
|
||||||
currentCount = CountNotifiers()
|
|
||||||
|
|
||||||
t.Run("New Emailer", func(t *testing.T) {
|
|
||||||
Emailer.Host = EMAIL_HOST
|
|
||||||
Emailer.Username = EMAIL_USER
|
|
||||||
Emailer.Password = EMAIL_PASS
|
|
||||||
Emailer.Var1 = EMAIL_OUTGOING
|
|
||||||
Emailer.Var2 = EMAIL_SEND_TO
|
|
||||||
Emailer.Port = int(EMAIL_PORT)
|
|
||||||
Emailer.Delay = time.Duration(100 * time.Millisecond)
|
|
||||||
|
|
||||||
testEmail = &emailOutgoing{
|
|
||||||
To: Emailer.GetValue("var2"),
|
|
||||||
Subject: fmt.Sprintf("Service %v is Failing", TestService.Name),
|
|
||||||
Template: mainEmailTemplate,
|
|
||||||
Data: TestService,
|
|
||||||
From: Emailer.GetValue("var1"),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Add email Notifier", func(t *testing.T) {
|
|
||||||
err := AddNotifiers(Emailer)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "Hunter Long", Emailer.Author)
|
|
||||||
assert.Equal(t, EMAIL_HOST, Emailer.Host)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("email Within Limits", func(t *testing.T) {
|
|
||||||
ok, err := Emailer.WithinLimits()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("email Test Source", func(t *testing.T) {
|
|
||||||
emailSource(testEmail)
|
|
||||||
assert.NotEmpty(t, testEmail.Source)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("email OnFailure", func(t *testing.T) {
|
|
||||||
Emailer.OnFailure(TestService, TestFailure)
|
|
||||||
assert.Equal(t, 1, len(Emailer.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("email OnSuccess", func(t *testing.T) {
|
|
||||||
Emailer.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Emailer.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("email Check Back Online", func(t *testing.T) {
|
|
||||||
assert.True(t, TestService.Online)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("email OnSuccess Again", func(t *testing.T) {
|
|
||||||
Emailer.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Emailer.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("email Send", func(t *testing.T) {
|
|
||||||
err := Emailer.Send(testEmail)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Emailer Test", func(t *testing.T) {
|
|
||||||
t.SkipNow()
|
|
||||||
err := Emailer.OnTest()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("email Run Queue", func(t *testing.T) {
|
|
||||||
go notifications.Queue(Emailer)
|
|
||||||
time.Sleep(6 * time.Second)
|
|
||||||
assert.Equal(t, EMAIL_HOST, Emailer.Host)
|
|
||||||
assert.Equal(t, 0, len(Emailer.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -26,8 +26,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ notifications.Notifier = (*lineNotifier)(nil)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
lineNotifyMethod = "line notify"
|
lineNotifyMethod = "line_notify"
|
||||||
)
|
)
|
||||||
|
|
||||||
type lineNotifier struct {
|
type lineNotifier struct {
|
||||||
|
|
|
@ -26,6 +26,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ notifications.Notifier = (*mobilePush)(nil)
|
||||||
|
|
||||||
const mobileIdentifier = "com.statping"
|
const mobileIdentifier = "com.statping"
|
||||||
|
|
||||||
type mobilePush struct {
|
type mobilePush struct {
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
MOBILE_ID string
|
|
||||||
MOBILE_NUMBER string
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
MOBILE_ID = os.Getenv("MOBILE_ID")
|
|
||||||
MOBILE_NUMBER = os.Getenv("MOBILE_NUMBER")
|
|
||||||
Mobile.Var1 = MOBILE_ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMobileNotifier(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
Mobile.Var1 = MOBILE_ID
|
|
||||||
Mobile.Var2 = os.Getenv("MOBILE_NUMBER")
|
|
||||||
if MOBILE_ID == "" {
|
|
||||||
t.Log("Mobile notifier testing skipped, missing MOBILE_ID environment variable")
|
|
||||||
t.SkipNow()
|
|
||||||
}
|
|
||||||
currentCount = CountNotifiers()
|
|
||||||
|
|
||||||
t.Run("Load Mobile", func(t *testing.T) {
|
|
||||||
Mobile.Var1 = MOBILE_ID
|
|
||||||
Mobile.Var2 = MOBILE_NUMBER
|
|
||||||
Mobile.Delay = time.Duration(100 * time.Millisecond)
|
|
||||||
Mobile.Limits = 10
|
|
||||||
err := AddNotifiers(Mobile)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "Hunter Long", Mobile.Author)
|
|
||||||
assert.Equal(t, MOBILE_ID, Mobile.Var1)
|
|
||||||
assert.Equal(t, MOBILE_NUMBER, Mobile.Var2)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Mobile Notifier Tester", func(t *testing.T) {
|
|
||||||
assert.True(t, Mobile.CanTest())
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Mobile Within Limits", func(t *testing.T) {
|
|
||||||
ok, err := Mobile.WithinLimits()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Mobile OnFailure", func(t *testing.T) {
|
|
||||||
Mobile.OnFailure(TestService, TestFailure)
|
|
||||||
assert.Equal(t, 1, len(Mobile.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Mobile OnSuccess", func(t *testing.T) {
|
|
||||||
Mobile.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Mobile.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Mobile OnSuccess Again", func(t *testing.T) {
|
|
||||||
t.SkipNow()
|
|
||||||
assert.True(t, TestService.Online)
|
|
||||||
Mobile.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Mobile.Queue))
|
|
||||||
go notifications.Queue(Mobile)
|
|
||||||
time.Sleep(20 * time.Second)
|
|
||||||
assert.Equal(t, 1, len(Mobile.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Mobile Within Limits again", func(t *testing.T) {
|
|
||||||
ok, err := Mobile.WithinLimits()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Mobile Test", func(t *testing.T) {
|
|
||||||
t.SkipNow()
|
|
||||||
err := Mobile.OnTest()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Mobile Queue", func(t *testing.T) {
|
|
||||||
t.SkipNow()
|
|
||||||
go notifications.Queue(Mobile)
|
|
||||||
time.Sleep(15 * time.Second)
|
|
||||||
assert.Equal(t, MOBILE_ID, Mobile.Var1)
|
|
||||||
assert.Equal(t, 0, len(Mobile.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"github.com/google/martian/log"
|
"github.com/google/martian/log"
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
"github.com/hunterlong/statping/types/notifications"
|
||||||
"github.com/hunterlong/statping/utils"
|
"github.com/hunterlong/statping/utils"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,9 +12,8 @@ var (
|
||||||
allowedVars = []string{"host", "username", "password", "port", "api_key", "api_secret", "var1", "var2"}
|
allowedVars = []string{"host", "username", "password", "port", "api_key", "api_secret", "var1", "var2"}
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkNotifierForm(n notifications.Notifier) error {
|
func checkNotifierForm(n *notifications.Notification) error {
|
||||||
notifier := n.Select()
|
for _, f := range n.Form {
|
||||||
for _, f := range notifier.Form {
|
|
||||||
contains := contains(f.DbField, allowedVars)
|
contains := contains(f.DbField, allowedVars)
|
||||||
if !contains {
|
if !contains {
|
||||||
return fmt.Errorf("the DbField '%v' is not allowed, allowed vars: %v", f.DbField, allowedVars)
|
return fmt.Errorf("the DbField '%v' is not allowed, allowed vars: %v", f.DbField, allowedVars)
|
||||||
|
@ -35,34 +33,50 @@ func contains(s string, arr []string) bool {
|
||||||
|
|
||||||
// AddNotifier accept a Notifier interface to be added into the array
|
// AddNotifier accept a Notifier interface to be added into the array
|
||||||
func AddNotifiers(notifiers ...notifications.Notifier) error {
|
func AddNotifiers(notifiers ...notifications.Notifier) error {
|
||||||
|
log.Infof("Initiating %d Notifiers\n", len(notifiers))
|
||||||
|
|
||||||
for _, n := range notifiers {
|
for _, n := range notifiers {
|
||||||
log.Infof("Installing %s Notifier...", n.Select().Method)
|
notif := n.Select()
|
||||||
if err := checkNotifierForm(n); err != nil {
|
log.Infof("Initiating %s Notifier\n", notif.Method)
|
||||||
return errors.Wrap(err, "error with notifier form fields")
|
|
||||||
|
if err := checkNotifierForm(notif); err != nil {
|
||||||
|
log.Errorf(err.Error())
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
if _, err := notifications.Init(n); err != nil {
|
|
||||||
return errors.Wrap(err, "error initiating notifier")
|
log.Infof("Creating %s Notifier\n", notif.Method)
|
||||||
|
if err := notif.Create(); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notifications.Append(notif)
|
||||||
|
|
||||||
|
if notif.Enabled.Bool {
|
||||||
|
notif.Close()
|
||||||
|
notif.Start()
|
||||||
|
go notifications.Queue(notif)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
startAllNotifiers()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// startAllNotifiers will start the go routine for each loaded notifier
|
// startAllNotifiers will start the go routine for each loaded notifier
|
||||||
func startAllNotifiers() {
|
func startAllNotifiers() {
|
||||||
for _, comm := range notifications.AllCommunications {
|
for _, notify := range notifications.All() {
|
||||||
if utils.IsType(comm, new(notifications.Notifier)) {
|
n := notify.Select()
|
||||||
notify := comm.(notifications.Notifier)
|
log.Infof("Initiating %s Notifier\n", n.Method)
|
||||||
if notify.Select().Enabled.Bool {
|
if utils.IsType(notify, new(notifications.Notifier)) {
|
||||||
notify.Select().Close()
|
if n.Enabled.Bool {
|
||||||
notify.Select().Start()
|
n.Close()
|
||||||
|
n.Start()
|
||||||
go notifications.Queue(notify)
|
go notifications.Queue(notify)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AttachNotifiers() error {
|
func Migrate() error {
|
||||||
return AddNotifiers(
|
return AddNotifiers(
|
||||||
Command,
|
Command,
|
||||||
Discorder,
|
Discorder,
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"github.com/hunterlong/statping/database"
|
|
||||||
"github.com/hunterlong/statping/source"
|
|
||||||
"github.com/hunterlong/statping/types/failures"
|
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
|
||||||
"github.com/hunterlong/statping/types/null"
|
|
||||||
"github.com/hunterlong/statping/types/services"
|
|
||||||
"github.com/hunterlong/statping/types/users"
|
|
||||||
"github.com/hunterlong/statping/utils"
|
|
||||||
"github.com/jinzhu/gorm"
|
|
||||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
dir string
|
|
||||||
db *gorm.DB
|
|
||||||
currentCount int
|
|
||||||
)
|
|
||||||
|
|
||||||
var TestService = &services.Service{
|
|
||||||
Id: 1,
|
|
||||||
Name: "Interpol - All The Rage Back Home",
|
|
||||||
Domain: "https://www.youtube.com/watch?v=-u6DvRyyKGU",
|
|
||||||
ExpectedStatus: 200,
|
|
||||||
Expected: null.NewNullString("test example"),
|
|
||||||
Interval: 30,
|
|
||||||
Type: "http",
|
|
||||||
Method: "GET",
|
|
||||||
Timeout: 20,
|
|
||||||
LastStatusCode: 404,
|
|
||||||
Online: true,
|
|
||||||
LastResponse: "<html>this is an example response</html>",
|
|
||||||
CreatedAt: utils.Now().Add(-24 * time.Hour),
|
|
||||||
}
|
|
||||||
|
|
||||||
var TestFailure = &failures.Failure{
|
|
||||||
Issue: "testing",
|
|
||||||
Service: 1,
|
|
||||||
CreatedAt: utils.Now().Add(-12 * time.Hour),
|
|
||||||
}
|
|
||||||
|
|
||||||
var TestUser = &users.User{
|
|
||||||
Username: "admin",
|
|
||||||
Email: "info@email.com",
|
|
||||||
}
|
|
||||||
|
|
||||||
func CountNotifiers() int {
|
|
||||||
return len(notifications.AllCommunications)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
dir = utils.Directory
|
|
||||||
source.Assets()
|
|
||||||
utils.InitLogs()
|
|
||||||
injectDatabase()
|
|
||||||
}
|
|
||||||
|
|
||||||
func injectDatabase() {
|
|
||||||
utils.DeleteFile(dir + "/notifiers.db")
|
|
||||||
db, err := gorm.Open("sqlite3", dir+"/notifiers.db")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
db.CreateTable(¬ifications.Notification{})
|
|
||||||
notifications.SetDB(&database.Db{db, "sqlite3"})
|
|
||||||
}
|
|
|
@ -28,6 +28,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ notifications.Notifier = (*slack)(nil)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
slackMethod = "slack"
|
slackMethod = "slack"
|
||||||
failingTemplate = `{ "attachments": [ { "fallback": "Service {{.Service.Name}} - is currently failing", "text": "Your Statping service <{{.Service.Domain}}|{{.Service.Name}}> has just received a Failure notification based on your expected results. {{.Service.Name}} responded with a HTTP Status code of {{.Service.LastStatusCode}}.", "fields": [ { "title": "Expected Status Code", "value": "{{.Service.ExpectedStatus}}", "short": true }, { "title": "Received Status Code", "value": "{{.Service.LastStatusCode}}", "short": true } ,{ "title": "Error Message", "value": "{{.Issue}}", "short": false } ], "color": "#FF0000", "thumb_url": "https://statping.com", "footer": "Statping", "footer_icon": "https://img.cjx.io/statuplogo32.png" } ] }`
|
failingTemplate = `{ "attachments": [ { "fallback": "Service {{.Service.Name}} - is currently failing", "text": "Your Statping service <{{.Service.Domain}}|{{.Service.Name}}> has just received a Failure notification based on your expected results. {{.Service.Name}} responded with a HTTP Status code of {{.Service.LastStatusCode}}.", "fields": [ { "title": "Expected Status Code", "value": "{{.Service.ExpectedStatus}}", "short": true }, { "title": "Received Status Code", "value": "{{.Service.LastStatusCode}}", "short": true } ,{ "title": "Error Message", "value": "{{.Issue}}", "short": false } ], "color": "#FF0000", "thumb_url": "https://statping.com", "footer": "Statping", "footer_icon": "https://img.cjx.io/statuplogo32.png" } ] }`
|
||||||
|
|
|
@ -1,115 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
SLACK_URL string
|
|
||||||
slackTestMessage = `{"text":"this is a test from the slack notifier!"}`
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
SLACK_URL = os.Getenv("SLACK_URL")
|
|
||||||
Slacker.Host = SLACK_URL
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSlackNotifier(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
SLACK_URL = os.Getenv("SLACK_URL")
|
|
||||||
Slacker.Host = SLACK_URL
|
|
||||||
if SLACK_URL == "" {
|
|
||||||
t.Log("slack notifier testing skipped, missing SLACK_URL environment variable")
|
|
||||||
t.SkipNow()
|
|
||||||
}
|
|
||||||
currentCount = CountNotifiers()
|
|
||||||
|
|
||||||
t.Run("Load slack", func(t *testing.T) {
|
|
||||||
Slacker.Host = SLACK_URL
|
|
||||||
Slacker.Delay = time.Duration(100 * time.Millisecond)
|
|
||||||
Slacker.Limits = 3
|
|
||||||
err := AddNotifiers(Slacker)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "Hunter Long", Slacker.Author)
|
|
||||||
assert.Equal(t, SLACK_URL, Slacker.Host)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("slack Notifier Tester", func(t *testing.T) {
|
|
||||||
assert.True(t, Slacker.CanTest())
|
|
||||||
})
|
|
||||||
|
|
||||||
//t.Run("slack parse message", func(t *testing.T) {
|
|
||||||
// err := parseSlackMessage(slackText, "this is a test!")
|
|
||||||
// assert.Nil(t, err)
|
|
||||||
// assert.Equal(t, 1, len(Slacker.Queue))
|
|
||||||
//})
|
|
||||||
|
|
||||||
t.Run("slack Within Limits", func(t *testing.T) {
|
|
||||||
ok, err := Slacker.WithinLimits()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("slack OnFailure", func(t *testing.T) {
|
|
||||||
Slacker.OnFailure(TestService, TestFailure)
|
|
||||||
assert.Equal(t, 1, len(Slacker.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("slack OnSuccess", func(t *testing.T) {
|
|
||||||
Slacker.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Slacker.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("slack OnSuccess Again", func(t *testing.T) {
|
|
||||||
assert.True(t, TestService.Online)
|
|
||||||
Slacker.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Slacker.Queue))
|
|
||||||
go notifications.Queue(Slacker)
|
|
||||||
time.Sleep(15 * time.Second)
|
|
||||||
assert.Equal(t, 0, len(Slacker.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("slack Within Limits again", func(t *testing.T) {
|
|
||||||
ok, err := Slacker.WithinLimits()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("slack Send", func(t *testing.T) {
|
|
||||||
err := Slacker.Send(slackTestMessage)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, 0, len(Slacker.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("slack Test", func(t *testing.T) {
|
|
||||||
err := Slacker.OnTest()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("slack Queue", func(t *testing.T) {
|
|
||||||
go notifications.Queue(Slacker)
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
assert.Equal(t, SLACK_URL, Slacker.Host)
|
|
||||||
assert.Equal(t, 0, len(Slacker.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -28,6 +28,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ notifications.Notifier = (*telegram)(nil)
|
||||||
|
|
||||||
type telegram struct {
|
type telegram struct {
|
||||||
*notifications.Notification
|
*notifications.Notification
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,105 +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/statping
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
telegramToken string
|
|
||||||
telegramChannel string
|
|
||||||
telegramMessage = "The Telegram notifier on Statping has been tested!"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
telegramToken = os.Getenv("TELEGRAM_TOKEN")
|
|
||||||
telegramChannel = os.Getenv("TELEGRAM_CHANNEL")
|
|
||||||
Telegram.ApiSecret = telegramToken
|
|
||||||
Telegram.Var1 = telegramChannel
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTelegramNotifier(t *testing.T) {
|
|
||||||
t.SkipNow()
|
|
||||||
t.Parallel()
|
|
||||||
if telegramToken == "" || telegramChannel == "" {
|
|
||||||
t.Log("Telegram notifier testing skipped, missing TELEGRAM_TOKEN and TELEGRAM_CHANNEL environment variable")
|
|
||||||
t.SkipNow()
|
|
||||||
}
|
|
||||||
currentCount = CountNotifiers()
|
|
||||||
|
|
||||||
t.Run("Load Telegram", func(t *testing.T) {
|
|
||||||
Telegram.ApiSecret = telegramToken
|
|
||||||
Telegram.Var1 = telegramChannel
|
|
||||||
Telegram.Delay = time.Duration(1 * time.Second)
|
|
||||||
err := AddNotifiers(Telegram)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "Hunter Long", Telegram.Author)
|
|
||||||
assert.Equal(t, telegramToken, Telegram.ApiSecret)
|
|
||||||
assert.Equal(t, telegramChannel, Telegram.Var1)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Telegram Within Limits", func(t *testing.T) {
|
|
||||||
ok, err := Telegram.WithinLimits()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Telegram OnFailure", func(t *testing.T) {
|
|
||||||
Telegram.OnFailure(TestService, TestFailure)
|
|
||||||
assert.Equal(t, 1, len(Telegram.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Telegram Check Offline", func(t *testing.T) {
|
|
||||||
assert.False(t, TestService.Online)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Telegram OnSuccess", func(t *testing.T) {
|
|
||||||
Telegram.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Telegram.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Telegram Check Back Online", func(t *testing.T) {
|
|
||||||
assert.True(t, TestService.Online)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Telegram OnSuccess Again", func(t *testing.T) {
|
|
||||||
Telegram.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, 1, len(Telegram.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Telegram Send", func(t *testing.T) {
|
|
||||||
err := Telegram.Send(telegramMessage)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Telegram Test", func(t *testing.T) {
|
|
||||||
err := Telegram.OnTest()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Telegram Queue", func(t *testing.T) {
|
|
||||||
go notifications.Queue(Telegram)
|
|
||||||
time.Sleep(3 * time.Second)
|
|
||||||
assert.Equal(t, telegramToken, Telegram.ApiSecret)
|
|
||||||
assert.Equal(t, 0, len(Telegram.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -28,6 +28,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ notifications.Notifier = (*twilio)(nil)
|
||||||
|
|
||||||
type twilio struct {
|
type twilio struct {
|
||||||
*notifications.Notification
|
*notifications.Notification
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
TWILIO_SID = os.Getenv("TWILIO_SID")
|
|
||||||
TWILIO_SECRET = os.Getenv("TWILIO_SECRET")
|
|
||||||
TWILIO_FROM = os.Getenv("TWILIO_FROM")
|
|
||||||
TWILIO_TO = os.Getenv("TWILIO_TO")
|
|
||||||
twilioMessage = "The Twilio notifier on Statping has been tested!"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
TWILIO_SID = os.Getenv("TWILIO_SID")
|
|
||||||
TWILIO_SECRET = os.Getenv("TWILIO_SECRET")
|
|
||||||
TWILIO_FROM = os.Getenv("TWILIO_FROM")
|
|
||||||
TWILIO_TO = os.Getenv("TWILIO_TO")
|
|
||||||
|
|
||||||
Twilio.ApiKey = TWILIO_SID
|
|
||||||
Twilio.ApiSecret = TWILIO_SECRET
|
|
||||||
Twilio.Var1 = TWILIO_TO
|
|
||||||
Twilio.Var2 = TWILIO_FROM
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTwilioNotifier(t *testing.T) {
|
|
||||||
t.SkipNow()
|
|
||||||
if TWILIO_SID == "" || TWILIO_SECRET == "" || TWILIO_FROM == "" {
|
|
||||||
t.Log("twilio notifier testing skipped, missing TWILIO_SID environment variable")
|
|
||||||
t.SkipNow()
|
|
||||||
}
|
|
||||||
currentCount = CountNotifiers()
|
|
||||||
|
|
||||||
t.Run("Load Twilio", func(t *testing.T) {
|
|
||||||
Twilio.ApiKey = TWILIO_SID
|
|
||||||
Twilio.Delay = time.Duration(100 * time.Millisecond)
|
|
||||||
err := AddNotifiers(Twilio)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "Hunter Long", Twilio.Author)
|
|
||||||
assert.Equal(t, TWILIO_SID, Twilio.ApiKey)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Twilio Within Limits", func(t *testing.T) {
|
|
||||||
ok, err := Twilio.WithinLimits()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Twilio OnFailure", func(t *testing.T) {
|
|
||||||
Twilio.OnFailure(TestService, TestFailure)
|
|
||||||
assert.Len(t, Twilio.Queue, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Twilio Check Offline", func(t *testing.T) {
|
|
||||||
assert.False(t, TestService.Online)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Twilio OnSuccess", func(t *testing.T) {
|
|
||||||
Twilio.OnSuccess(TestService)
|
|
||||||
assert.Len(t, Twilio.Queue, 2)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Twilio Check Back Online", func(t *testing.T) {
|
|
||||||
assert.True(t, TestService.Online)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Twilio OnSuccess Again", func(t *testing.T) {
|
|
||||||
Twilio.OnSuccess(TestService)
|
|
||||||
assert.Len(t, Twilio.Queue, 2)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Twilio Send", func(t *testing.T) {
|
|
||||||
err := Twilio.Send(twilioMessage)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Twilio Test", func(t *testing.T) {
|
|
||||||
err := Twilio.OnTest()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Twilio Queue", func(t *testing.T) {
|
|
||||||
go notifications.Queue(Twilio)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
assert.Equal(t, TWILIO_SID, Twilio.ApiKey)
|
|
||||||
assert.Equal(t, 0, len(Twilio.Queue))
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -28,8 +28,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ notifications.Notifier = (*webhooker)(nil)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
webhookMethod = "Webhook"
|
webhookMethod = "webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
type webhooker struct {
|
type webhooker struct {
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 (
|
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
webhookTestUrl = "https://statping.com"
|
|
||||||
webhookMessage = `{"id": "%service.Id","name": "%service.Name","online": "%service.Online","issue": "%failure.Issue"}`
|
|
||||||
apiKey = "application/json"
|
|
||||||
fullMsg string
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
Webhook.Host = webhookTestUrl
|
|
||||||
Webhook.Var1 = "POST"
|
|
||||||
Webhook.Var2 = webhookMessage
|
|
||||||
Webhook.ApiKey = "application/json"
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWebhookNotifier(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
currentCount = CountNotifiers()
|
|
||||||
|
|
||||||
t.Run("Load webhooker", func(t *testing.T) {
|
|
||||||
Webhook.Host = webhookTestUrl
|
|
||||||
Webhook.Delay = time.Duration(100 * time.Millisecond)
|
|
||||||
Webhook.ApiKey = apiKey
|
|
||||||
err := AddNotifiers(Webhook)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "Hunter Long", Webhook.Author)
|
|
||||||
assert.Equal(t, webhookTestUrl, Webhook.Host)
|
|
||||||
assert.Equal(t, apiKey, Webhook.ApiKey)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("webhooker Notifier Tester", func(t *testing.T) {
|
|
||||||
assert.True(t, Webhook.CanTest())
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("webhooker Replace Body Text", func(t *testing.T) {
|
|
||||||
fullMsg = replaceBodyText(webhookMessage, TestService, TestFailure)
|
|
||||||
assert.Equal(t, `{"id": "1","name": "Interpol - All The Rage Back Home","online": "true","issue": "testing"}`, fullMsg)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("webhooker Within Limits", func(t *testing.T) {
|
|
||||||
ok, err := Webhook.WithinLimits()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, ok)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("webhooker OnFailure", func(t *testing.T) {
|
|
||||||
Webhook.OnFailure(TestService, TestFailure)
|
|
||||||
assert.Len(t, Webhook.Queue, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("webhooker OnSuccess", func(t *testing.T) {
|
|
||||||
Webhook.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, len(Webhook.Queue), 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("webhooker Check Back Online", func(t *testing.T) {
|
|
||||||
assert.True(t, TestService.Online)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("webhooker OnSuccess Again", func(t *testing.T) {
|
|
||||||
Webhook.OnSuccess(TestService)
|
|
||||||
assert.Equal(t, len(Webhook.Queue), 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("webhooker Send", func(t *testing.T) {
|
|
||||||
err := Webhook.Send(fullMsg)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, len(Webhook.Queue), 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("webhooker Queue", func(t *testing.T) {
|
|
||||||
go notifications.Queue(Webhook)
|
|
||||||
time.Sleep(8 * time.Second)
|
|
||||||
assert.Equal(t, webhookTestUrl, Webhook.Host)
|
|
||||||
assert.Equal(t, len(Webhook.Queue), 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Samples() {
|
func Samples() error {
|
||||||
checkin1 := &Checkin{
|
checkin1 := &Checkin{
|
||||||
Name: "Example Checkin 1",
|
Name: "Example Checkin 1",
|
||||||
ServiceId: 1,
|
ServiceId: 1,
|
||||||
|
@ -13,7 +13,9 @@ func Samples() {
|
||||||
GracePeriod: 300,
|
GracePeriod: 300,
|
||||||
ApiKey: utils.RandomString(7),
|
ApiKey: utils.RandomString(7),
|
||||||
}
|
}
|
||||||
checkin1.Create()
|
if err := checkin1.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
checkin2 := &Checkin{
|
checkin2 := &Checkin{
|
||||||
Name: "Example Checkin 2",
|
Name: "Example Checkin 2",
|
||||||
|
@ -22,10 +24,13 @@ func Samples() {
|
||||||
GracePeriod: 300,
|
GracePeriod: 300,
|
||||||
ApiKey: utils.RandomString(7),
|
ApiKey: utils.RandomString(7),
|
||||||
}
|
}
|
||||||
checkin2.Create()
|
if err := checkin2.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SamplesChkHits() {
|
func SamplesChkHits() error {
|
||||||
checkTime := time.Now().UTC().Add(-24 * time.Hour)
|
checkTime := time.Now().UTC().Add(-24 * time.Hour)
|
||||||
|
|
||||||
for i := int64(1); i <= 2; i++ {
|
for i := int64(1); i <= 2; i++ {
|
||||||
|
@ -35,8 +40,12 @@ func SamplesChkHits() {
|
||||||
CreatedAt: checkTime.UTC(),
|
CreatedAt: checkTime.UTC(),
|
||||||
}
|
}
|
||||||
|
|
||||||
checkHit.Create()
|
if err := checkHit.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
checkTime = checkTime.Add(10 * time.Minute)
|
checkTime = checkTime.Add(10 * time.Minute)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
package configs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hunterlong/statping/utils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
testConfigs *DbConfig
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDbConfig_Save(t *testing.T) {
|
|
||||||
config := &DbConfig{
|
|
||||||
DbConn: "sqlite",
|
|
||||||
Project: "Tester",
|
|
||||||
Location: utils.Directory,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := ConnectConfigs(config, true)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
err = config.Save(utils.Directory)
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, "sqlite3", config.DbConn)
|
|
||||||
assert.NotEmpty(t, config.ApiKey)
|
|
||||||
assert.NotEmpty(t, config.ApiSecret)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLoadDbConfig(t *testing.T) {
|
|
||||||
Configs, err := LoadConfigFile(utils.Directory)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "sqlite3", Configs.DbConn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEnvToConfig(t *testing.T) {
|
|
||||||
os.Setenv("DB_CONN", "sqlite")
|
|
||||||
os.Setenv("DB_USER", "")
|
|
||||||
os.Setenv("DB_PASS", "")
|
|
||||||
os.Setenv("DB_DATABASE", "")
|
|
||||||
os.Setenv("NAME", "Testing")
|
|
||||||
os.Setenv("DOMAIN", "http://localhost:8080")
|
|
||||||
os.Setenv("DESCRIPTION", "Testing Statping")
|
|
||||||
os.Setenv("ADMIN_USER", "admin")
|
|
||||||
os.Setenv("ADMIN_PASS", "admin123")
|
|
||||||
os.Setenv("VERBOSE", "1")
|
|
||||||
config, err := loadConfigEnvs()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, config.DbConn, "sqlite")
|
|
||||||
assert.Equal(t, config.Domain, "http://localhost:8080")
|
|
||||||
assert.Equal(t, config.Description, "Testing Statping")
|
|
||||||
assert.Equal(t, config.Username, "admin")
|
|
||||||
assert.Equal(t, config.Password, "admin123")
|
|
||||||
|
|
||||||
testConfigs = config
|
|
||||||
}
|
|
|
@ -84,21 +84,9 @@ func Connect(configs *DbConfig, retry bool) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitialSetup(configs *DbConfig) error {
|
func CreateAdminUser(configs *DbConfig) error {
|
||||||
log.Infoln(fmt.Sprintf("Core database does not exist, creating now!"))
|
log.Infoln(fmt.Sprintf("Core database does not exist, creating now!"))
|
||||||
|
|
||||||
if err := configs.DropDatabase(); err != nil {
|
|
||||||
return errors.Wrap(err, "error dropping database")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := CreateDatabase(); err != nil {
|
|
||||||
return errors.Wrap(err, "error creating database")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := TriggerSamples(); err != nil {
|
|
||||||
return errors.Wrap(err, "error creating database")
|
|
||||||
}
|
|
||||||
|
|
||||||
if configs.Username == "" && configs.Password == "" {
|
if configs.Username == "" && configs.Password == "" {
|
||||||
configs.Username = utils.Getenv("ADMIN_USER", "admin").(string)
|
configs.Username = utils.Getenv("ADMIN_USER", "admin").(string)
|
||||||
configs.Password = utils.Getenv("ADMIN_PASSWORD", "admin").(string)
|
configs.Password = utils.Getenv("ADMIN_PASSWORD", "admin").(string)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/hunterlong/statping/types/groups"
|
"github.com/hunterlong/statping/types/groups"
|
||||||
"github.com/hunterlong/statping/types/hits"
|
"github.com/hunterlong/statping/types/hits"
|
||||||
"github.com/hunterlong/statping/types/incidents"
|
"github.com/hunterlong/statping/types/incidents"
|
||||||
"github.com/hunterlong/statping/types/integrations"
|
|
||||||
"github.com/hunterlong/statping/types/messages"
|
"github.com/hunterlong/statping/types/messages"
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
"github.com/hunterlong/statping/types/notifications"
|
||||||
"github.com/hunterlong/statping/types/services"
|
"github.com/hunterlong/statping/types/services"
|
||||||
|
@ -18,7 +17,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SamplerFunc func()
|
type SamplerFunc func() error
|
||||||
|
|
||||||
type Sampler interface {
|
type Sampler interface {
|
||||||
Samples() []database.DbObject
|
Samples() []database.DbObject
|
||||||
|
@ -27,7 +26,7 @@ type Sampler interface {
|
||||||
func TriggerSamples() error {
|
func TriggerSamples() error {
|
||||||
return createSamples(
|
return createSamples(
|
||||||
core.Samples,
|
core.Samples,
|
||||||
users.Samples,
|
//users.Samples,
|
||||||
messages.Samples,
|
messages.Samples,
|
||||||
services.Samples,
|
services.Samples,
|
||||||
checkins.Samples,
|
checkins.Samples,
|
||||||
|
@ -42,7 +41,9 @@ func TriggerSamples() error {
|
||||||
|
|
||||||
func createSamples(sm ...SamplerFunc) error {
|
func createSamples(sm ...SamplerFunc) error {
|
||||||
for _, v := range sm {
|
for _, v := range sm {
|
||||||
v()
|
if err := v(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -72,7 +73,7 @@ func (d *DbConfig) Delete() error {
|
||||||
|
|
||||||
// DropDatabase will DROP each table Statping created
|
// DropDatabase will DROP each table Statping created
|
||||||
func (d *DbConfig) DropDatabase() error {
|
func (d *DbConfig) DropDatabase() error {
|
||||||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}, &integrations.Integration{}}
|
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||||
log.Infoln("Dropping Database Tables...")
|
log.Infoln("Dropping Database Tables...")
|
||||||
for _, t := range DbModels {
|
for _, t := range DbModels {
|
||||||
if err := database.DB().DropTableIfExists(t); err != nil {
|
if err := database.DB().DropTableIfExists(t); err != nil {
|
||||||
|
@ -87,7 +88,7 @@ func (d *DbConfig) DropDatabase() error {
|
||||||
func CreateDatabase() error {
|
func CreateDatabase() error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}, &integrations.Integration{}}
|
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||||
|
|
||||||
log.Infoln("Creating Database Tables...")
|
log.Infoln("Creating Database Tables...")
|
||||||
for _, table := range DbModels {
|
for _, table := range DbModels {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package configs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hunterlong/statping/database"
|
|
||||||
"github.com/hunterlong/statping/utils"
|
"github.com/hunterlong/statping/utils"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"os"
|
"os"
|
||||||
|
@ -11,7 +10,7 @@ import (
|
||||||
|
|
||||||
var log = utils.Log
|
var log = utils.Log
|
||||||
|
|
||||||
func ConnectConfigs(configs *DbConfig, initiate bool) error {
|
func ConnectConfigs(configs *DbConfig) error {
|
||||||
err := Connect(configs, true)
|
err := Connect(configs, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "error connecting to database")
|
return errors.Wrap(err, "error connecting to database")
|
||||||
|
@ -20,10 +19,6 @@ func ConnectConfigs(configs *DbConfig, initiate bool) error {
|
||||||
return errors.Wrap(err, "error saving configuration")
|
return errors.Wrap(err, "error saving configuration")
|
||||||
}
|
}
|
||||||
|
|
||||||
exists := database.DB().HasTable("core")
|
|
||||||
if !exists && initiate {
|
|
||||||
return InitialSetup(configs)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"github.com/hunterlong/statping/types/groups"
|
"github.com/hunterlong/statping/types/groups"
|
||||||
"github.com/hunterlong/statping/types/hits"
|
"github.com/hunterlong/statping/types/hits"
|
||||||
"github.com/hunterlong/statping/types/incidents"
|
"github.com/hunterlong/statping/types/incidents"
|
||||||
"github.com/hunterlong/statping/types/integrations"
|
|
||||||
"github.com/hunterlong/statping/types/messages"
|
"github.com/hunterlong/statping/types/messages"
|
||||||
"github.com/hunterlong/statping/types/notifications"
|
"github.com/hunterlong/statping/types/notifications"
|
||||||
"github.com/hunterlong/statping/types/services"
|
"github.com/hunterlong/statping/types/services"
|
||||||
|
@ -49,7 +48,7 @@ import (
|
||||||
//If this function has an issue, it will ROLLBACK to the previous state.
|
//If this function has an issue, it will ROLLBACK to the previous state.
|
||||||
func (c *DbConfig) MigrateDatabase() error {
|
func (c *DbConfig) MigrateDatabase() error {
|
||||||
|
|
||||||
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}, &integrations.Integration{}}
|
var DbModels = []interface{}{&services.Service{}, &users.User{}, &hits.Hit{}, &failures.Failure{}, &messages.Message{}, &groups.Group{}, &checkins.Checkin{}, &checkins.CheckinHit{}, ¬ifications.Notification{}, &incidents.Incident{}, &incidents.IncidentUpdate{}}
|
||||||
|
|
||||||
log.Infoln("Migrating Database Tables...")
|
log.Infoln("Migrating Database Tables...")
|
||||||
tx := database.Begin("migration")
|
tx := database.Begin("migration")
|
||||||
|
@ -91,8 +90,7 @@ func (c *DbConfig) MigrateDatabase() error {
|
||||||
if err := database.DB().Model(&failures.Failure{}).AddIndex("idx_checkin_fail", "checkin").Error(); err != nil {
|
if err := database.DB().Model(&failures.Failure{}).AddIndex("idx_checkin_fail", "checkin").Error(); err != nil {
|
||||||
log.Errorln(err)
|
log.Errorln(err)
|
||||||
}
|
}
|
||||||
|
log.Infoln("Database Indexes Created")
|
||||||
log.Infoln("Statping Database Indexes Migrated")
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hunterlong/statping/database"
|
"github.com/hunterlong/statping/database"
|
||||||
"github.com/hunterlong/statping/notifiers"
|
|
||||||
"github.com/hunterlong/statping/types/services"
|
"github.com/hunterlong/statping/types/services"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,27 +9,11 @@ func InitApp() error {
|
||||||
if _, err := Select(); err != nil {
|
if _, err := Select(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
//if err := InsertNotifierDB(); err != nil {
|
|
||||||
// return err
|
|
||||||
//}
|
|
||||||
//if err := InsertIntegratorDB(); err != nil {
|
|
||||||
// return err
|
|
||||||
//}
|
|
||||||
|
|
||||||
if _, err := services.SelectAllServices(true); err != nil {
|
if _, err := services.SelectAllServices(true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := notifiers.AttachNotifiers(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
//App.Notifications = notifications.AllCommunications
|
|
||||||
//if err := integrations.AddIntegrations(); err != nil {
|
|
||||||
// return err
|
|
||||||
//}
|
|
||||||
//App.Integrations = integrations.Integrations
|
|
||||||
|
|
||||||
go services.CheckServices()
|
go services.CheckServices()
|
||||||
|
|
||||||
database.StartMaintenceRoutine()
|
database.StartMaintenceRoutine()
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Samples() {
|
func Samples() error {
|
||||||
apiKey := utils.Getenv("API_KEY", "samplekey")
|
apiKey := utils.Getenv("API_KEY", "samplekey")
|
||||||
apiSecret := utils.Getenv("API_SECRET", "samplesecret")
|
apiSecret := utils.Getenv("API_SECRET", "samplesecret")
|
||||||
|
|
||||||
|
@ -21,5 +21,6 @@ func Samples() {
|
||||||
UseCdn: null.NewNullBool(false),
|
UseCdn: null.NewNullBool(false),
|
||||||
Footer: null.NewNullString(""),
|
Footer: null.NewNullString(""),
|
||||||
}
|
}
|
||||||
core.Create()
|
|
||||||
|
return core.Create()
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,13 @@ type Core struct {
|
||||||
Image string `gorm:"image" json:"started_on"`
|
Image string `gorm:"image" json:"started_on"`
|
||||||
Notifications []AllNotifiers `gorm:"-" json:"-"`
|
Notifications []AllNotifiers `gorm:"-" json:"-"`
|
||||||
Integrations []Integrator `gorm:"-" json:"-"`
|
Integrations []Integrator `gorm:"-" json:"-"`
|
||||||
|
|
||||||
|
GHAuth
|
||||||
|
}
|
||||||
|
|
||||||
|
type GHAuth struct {
|
||||||
|
GithubClientID string `gorm:"gh_client_id" json:"gh_client_id"`
|
||||||
|
GithubClientSecret string `gorm:"gh_client_secret" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllNotifiers contains all the Notifiers loaded
|
// AllNotifiers contains all the Notifiers loaded
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Samples() {
|
func Samples() error {
|
||||||
tx := DB().Begin()
|
tx := DB().Begin()
|
||||||
sg := new(sync.WaitGroup)
|
sg := new(sync.WaitGroup)
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ func Samples() {
|
||||||
for i := int64(1); i <= 4; i++ {
|
for i := int64(1); i <= 4; i++ {
|
||||||
sg.Add(1)
|
sg.Add(1)
|
||||||
|
|
||||||
log.Infoln(fmt.Sprintf("Adding %v Failure records to service", 730))
|
log.Infoln(fmt.Sprintf("Adding %v Failure records to service", 400))
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer sg.Done()
|
defer sg.Done()
|
||||||
|
@ -42,6 +42,8 @@ func Samples() {
|
||||||
|
|
||||||
if err := tx.Commit().Error(); err != nil {
|
if err := tx.Commit().Error(); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
package groups
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGroup_Create(t *testing.T) {
|
|
||||||
group := &Group{
|
|
||||||
Name: "Testing",
|
|
||||||
}
|
|
||||||
err := group.Create()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.NotZero(t, group.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGroup_Services(t *testing.T) {
|
|
||||||
group, err := Find(1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.NotEmpty(t, group.Services())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectGroups(t *testing.T) {
|
|
||||||
grs := SelectGroups(true, false)
|
|
||||||
assert.Equal(t, int(3), len(grs))
|
|
||||||
grs = SelectGroups(true, true)
|
|
||||||
assert.Equal(t, int(5), len(grs))
|
|
||||||
}
|
|
|
@ -4,26 +4,33 @@ import (
|
||||||
"github.com/hunterlong/statping/types/null"
|
"github.com/hunterlong/statping/types/null"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Samples() {
|
func Samples() error {
|
||||||
group1 := &Group{
|
group1 := &Group{
|
||||||
Name: "Main Services",
|
Name: "Main Services",
|
||||||
Public: null.NewNullBool(true),
|
Public: null.NewNullBool(true),
|
||||||
Order: 2,
|
Order: 2,
|
||||||
}
|
}
|
||||||
group1.Create()
|
if err := group1.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
group2 := &Group{
|
group2 := &Group{
|
||||||
Name: "Linked Services",
|
Name: "Linked Services",
|
||||||
Public: null.NewNullBool(false),
|
Public: null.NewNullBool(false),
|
||||||
Order: 1,
|
Order: 1,
|
||||||
}
|
}
|
||||||
group2.Create()
|
if err := group2.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
group3 := &Group{
|
group3 := &Group{
|
||||||
Name: "Empty Group",
|
Name: "Empty Group",
|
||||||
Public: null.NewNullBool(false),
|
Public: null.NewNullBool(false),
|
||||||
Order: 3,
|
Order: 3,
|
||||||
}
|
}
|
||||||
group3.Create()
|
if err := group3.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package hits
|
package hits
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/hunterlong/statping/database"
|
"github.com/hunterlong/statping/database"
|
||||||
"github.com/hunterlong/statping/types"
|
"github.com/hunterlong/statping/types"
|
||||||
"github.com/hunterlong/statping/utils"
|
"github.com/hunterlong/statping/utils"
|
||||||
|
@ -14,7 +15,7 @@ import (
|
||||||
|
|
||||||
var SampleHits = 99900.
|
var SampleHits = 99900.
|
||||||
|
|
||||||
func Samples() {
|
func Samples() error {
|
||||||
tx := DB().Begin()
|
tx := DB().Begin()
|
||||||
sg := new(sync.WaitGroup)
|
sg := new(sync.WaitGroup)
|
||||||
|
|
||||||
|
@ -26,9 +27,12 @@ func Samples() {
|
||||||
tx = DB().Begin()
|
tx = DB().Begin()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return tx.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
func createHitsAt(db database.Database, serviceID int64, sg *sync.WaitGroup) error {
|
func createHitsAt(db database.Database, serviceID int64, sg *sync.WaitGroup) error {
|
||||||
|
log.Infoln(fmt.Sprintf("Adding sample hit records to service #%d", serviceID))
|
||||||
|
|
||||||
createdAt := utils.Now().Add(-3 * types.Day)
|
createdAt := utils.Now().Add(-3 * types.Day)
|
||||||
p := utils.NewPerlin(2, 2, 5, utils.Now().UnixNano())
|
p := utils.NewPerlin(2, 2, 5, utils.Now().UnixNano())
|
||||||
|
|
||||||
|
@ -46,6 +50,10 @@ func createHitsAt(db database.Database, serviceID int64, sg *sync.WaitGroup) err
|
||||||
}
|
}
|
||||||
|
|
||||||
db = db.Create(&hit)
|
db = db.Create(&hit)
|
||||||
|
if err := db.Error(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
i++
|
i++
|
||||||
if createdAt.After(utils.Now()) {
|
if createdAt.After(utils.Now()) {
|
||||||
break
|
break
|
||||||
|
|
|
@ -1,40 +1,53 @@
|
||||||
package incidents
|
package incidents
|
||||||
|
|
||||||
func Samples() {
|
func Samples() error {
|
||||||
incident1 := &Incident{
|
incident1 := &Incident{
|
||||||
Title: "Github Downtime",
|
Title: "Github Downtime",
|
||||||
Description: "This is an example of a incident for a service.",
|
Description: "This is an example of a incident for a service.",
|
||||||
ServiceId: 2,
|
ServiceId: 2,
|
||||||
}
|
}
|
||||||
incident1.Create()
|
if err := incident1.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
i1 := &IncidentUpdate{
|
i1 := &IncidentUpdate{
|
||||||
IncidentId: incident1.Id,
|
IncidentId: incident1.Id,
|
||||||
Message: "Github's page for Statping seems to be sending a 501 error.",
|
Message: "Github's page for Statping seems to be sending a 501 error.",
|
||||||
Type: "Investigating",
|
Type: "Investigating",
|
||||||
}
|
}
|
||||||
i1.Create()
|
if err := i1.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
i2 := &IncidentUpdate{
|
i2 := &IncidentUpdate{
|
||||||
IncidentId: incident1.Id,
|
IncidentId: incident1.Id,
|
||||||
Message: "Problem is continuing and we are looking at the issues.",
|
Message: "Problem is continuing and we are looking at the issues.",
|
||||||
Type: "Update",
|
Type: "Update",
|
||||||
}
|
}
|
||||||
i2.Create()
|
if err := i2.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
i3 := &IncidentUpdate{
|
i3 := &IncidentUpdate{
|
||||||
IncidentId: incident1.Id,
|
IncidentId: incident1.Id,
|
||||||
Message: "Github is now back online and everything is working.",
|
Message: "Github is now back online and everything is working.",
|
||||||
Type: "Resolved",
|
Type: "Resolved",
|
||||||
}
|
}
|
||||||
i3.Create()
|
if err := i3.Create(); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func SamplesUpdates() {
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SamplesUpdates() error {
|
||||||
u1 := &IncidentUpdate{
|
u1 := &IncidentUpdate{
|
||||||
IncidentId: 1,
|
IncidentId: 1,
|
||||||
Message: "Github is now back online and everything is working.",
|
Message: "Github is now back online and everything is working.",
|
||||||
Type: "Resolved",
|
Type: "Resolved",
|
||||||
}
|
}
|
||||||
u1.Create()
|
if err := u1.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
package integrations
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hunterlong/statping/database"
|
|
||||||
"github.com/hunterlong/statping/types/services"
|
|
||||||
)
|
|
||||||
|
|
||||||
func DB() database.Database {
|
|
||||||
return database.DB().Model(&Integration{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Find(name string) (*Integration, error) {
|
|
||||||
var integration Integration
|
|
||||||
db := DB().Where("name = ?", name).Find(&integration)
|
|
||||||
return &integration, db.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func All() []*Integration {
|
|
||||||
var integrations []*Integration
|
|
||||||
DB().Find(&integrations)
|
|
||||||
return integrations
|
|
||||||
}
|
|
||||||
|
|
||||||
func List(i Integrator) ([]*services.Service, error) {
|
|
||||||
return i.List()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Integration) Create() error {
|
|
||||||
db := DB().Create(i)
|
|
||||||
return db.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Integration) Update() error {
|
|
||||||
db := DB().Update(i)
|
|
||||||
return db.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Integration) Delete() error {
|
|
||||||
db := DB().Delete(i)
|
|
||||||
return db.Error()
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package integrations
|
|
||||||
|
|
||||||
import "github.com/hunterlong/statping/types/services"
|
|
||||||
|
|
||||||
type Integration struct {
|
|
||||||
ShortName string `gorm:"column:name" json:"name"`
|
|
||||||
Name string `gorm:"-" json:"full_name,omitempty"`
|
|
||||||
Icon string `gorm:"-" json:"-"`
|
|
||||||
Description string `gorm:"-" json:"description,omitempty"`
|
|
||||||
Enabled bool `gorm:"column:enabled;default:false" json:"enabled"`
|
|
||||||
Fields []*IntegrationField `gorm:"column:fields" json:"fields"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type IntegrationField struct {
|
|
||||||
Name string `gorm:"-" json:"name"`
|
|
||||||
Value interface{} `gorm:"-" json:"value"`
|
|
||||||
Type string `gorm:"-" json:"type"`
|
|
||||||
Description string `gorm:"-" json:"description,omitempty"`
|
|
||||||
MimeType string `gorm:"-" json:"mime_type,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Integrator interface {
|
|
||||||
Get() *Integration
|
|
||||||
List() ([]*services.Service, error)
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Samples() {
|
func Samples() error {
|
||||||
m1 := &Message{
|
m1 := &Message{
|
||||||
Title: "Routine Downtime",
|
Title: "Routine Downtime",
|
||||||
Description: "This is an example a upcoming message for a service!",
|
Description: "This is an example a upcoming message for a service!",
|
||||||
|
@ -13,7 +13,9 @@ func Samples() {
|
||||||
EndOn: time.Now().UTC().Add(2 * time.Hour),
|
EndOn: time.Now().UTC().Add(2 * time.Hour),
|
||||||
}
|
}
|
||||||
|
|
||||||
m1.Create()
|
if err := m1.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
m2 := &Message{
|
m2 := &Message{
|
||||||
Title: "Server Reboot",
|
Title: "Server Reboot",
|
||||||
|
@ -23,5 +25,9 @@ func Samples() {
|
||||||
EndOn: time.Now().UTC().Add(2 * time.Hour),
|
EndOn: time.Now().UTC().Add(2 * time.Hour),
|
||||||
}
|
}
|
||||||
|
|
||||||
m2.Create()
|
if err := m2.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,12 @@ func DB() database.Database {
|
||||||
return database.DB().Model(&Notification{})
|
return database.DB().Model(&Notification{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Append(n Notifier) {
|
||||||
|
allNotifiers = append(allNotifiers, n)
|
||||||
|
}
|
||||||
|
|
||||||
func Find(name string) (Notifier, error) {
|
func Find(name string) (Notifier, error) {
|
||||||
for _, n := range AllCommunications {
|
for _, n := range allNotifiers {
|
||||||
notif := n.Select()
|
notif := n.Select()
|
||||||
if notif.Name() == name || notif.Method == name {
|
if notif.Name() == name || notif.Method == name {
|
||||||
return n, nil
|
return n, nil
|
||||||
|
@ -19,15 +23,16 @@ func Find(name string) (Notifier, error) {
|
||||||
return nil, errors.New("notifier not found")
|
return nil, errors.New("notifier not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func All() []*Notification {
|
func All() []Notifier {
|
||||||
var notifiers []*Notification
|
return allNotifiers
|
||||||
DB().Find(¬ifiers)
|
|
||||||
return notifiers
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) Create() error {
|
func (n *Notification) Create() error {
|
||||||
db := DB().FirstOrCreate(&n)
|
var notif Notification
|
||||||
return db.Error()
|
if DB().Where("method = ?", n.Method).Find(¬if).RecordNotFound() {
|
||||||
|
return DB().Create(n).Error()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Notification) Update() error {
|
func (n *Notification) Update() error {
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
|
|
||||||
// OnSave will trigger a notifier when it has been saved - Notifier interface
|
// OnSave will trigger a notifier when it has been saved - Notifier interface
|
||||||
func OnSave(method string) {
|
func OnSave(method string) {
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
if utils.IsType(comm, new(Notifier)) {
|
if utils.IsType(comm, new(Notifier)) {
|
||||||
notifier := comm.(Notifier)
|
notifier := comm.(Notifier)
|
||||||
if notifier.Select().Method == method {
|
if notifier.Select().Method == method {
|
||||||
|
@ -53,7 +53,7 @@ func OnFailure(s *services.Service, f *failures.Failure) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessages:
|
sendMessages:
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
if utils.IsType(comm, new(BasicEvents)) && isEnabled(comm) && (s.Online || inLimits(comm)) {
|
if utils.IsType(comm, new(BasicEvents)) && isEnabled(comm) && (s.Online || inLimits(comm)) {
|
||||||
notifier := comm.(Notifier).Select()
|
notifier := comm.(Notifier).Select()
|
||||||
log.
|
log.
|
||||||
|
@ -76,7 +76,7 @@ func OnSuccess(s *services.Service) {
|
||||||
s.UserNotified = false
|
s.UserNotified = false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
if utils.IsType(comm, new(BasicEvents)) && isEnabled(comm) && (!s.Online || inLimits(comm)) {
|
if utils.IsType(comm, new(BasicEvents)) && isEnabled(comm) && (!s.Online || inLimits(comm)) {
|
||||||
notifier := comm.(Notifier).Select()
|
notifier := comm.(Notifier).Select()
|
||||||
log.
|
log.
|
||||||
|
@ -90,7 +90,7 @@ func OnSuccess(s *services.Service) {
|
||||||
|
|
||||||
// OnNewService is triggered when a new service is created - ServiceEvents interface
|
// OnNewService is triggered when a new service is created - ServiceEvents interface
|
||||||
func OnNewService(s *services.Service) {
|
func OnNewService(s *services.Service) {
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
if utils.IsType(comm, new(ServiceEvents)) && isEnabled(comm) && inLimits(comm) {
|
if utils.IsType(comm, new(ServiceEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||||
log.
|
log.
|
||||||
WithField("trigger", "OnNewService").
|
WithField("trigger", "OnNewService").
|
||||||
|
@ -106,7 +106,7 @@ func OnUpdatedService(s *services.Service) {
|
||||||
if !s.AllowNotifications.Bool {
|
if !s.AllowNotifications.Bool {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
if utils.IsType(comm, new(ServiceEvents)) && isEnabled(comm) && inLimits(comm) {
|
if utils.IsType(comm, new(ServiceEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||||
log.Debugln(fmt.Sprintf("Sending updated service notification for service %v", s.Name))
|
log.Debugln(fmt.Sprintf("Sending updated service notification for service %v", s.Name))
|
||||||
comm.(ServiceEvents).OnUpdatedService(s)
|
comm.(ServiceEvents).OnUpdatedService(s)
|
||||||
|
@ -120,7 +120,7 @@ func OnDeletedService(s *services.Service) {
|
||||||
if !s.AllowNotifications.Bool {
|
if !s.AllowNotifications.Bool {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
if utils.IsType(comm, new(ServiceEvents)) && isEnabled(comm) && inLimits(comm) {
|
if utils.IsType(comm, new(ServiceEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||||
log.Debugln(fmt.Sprintf("Sending deleted service notification for service %v", s.Name))
|
log.Debugln(fmt.Sprintf("Sending deleted service notification for service %v", s.Name))
|
||||||
comm.(ServiceEvents).OnDeletedService(s)
|
comm.(ServiceEvents).OnDeletedService(s)
|
||||||
|
@ -131,7 +131,7 @@ func OnDeletedService(s *services.Service) {
|
||||||
|
|
||||||
// OnNewUser is triggered when a new user is created - UserEvents interface
|
// OnNewUser is triggered when a new user is created - UserEvents interface
|
||||||
func OnNewUser(u *users.User) {
|
func OnNewUser(u *users.User) {
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
if utils.IsType(comm, new(UserEvents)) && isEnabled(comm) && inLimits(comm) {
|
if utils.IsType(comm, new(UserEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||||
log.Debugln(fmt.Sprintf("Sending new user notification for user %v", u.Username))
|
log.Debugln(fmt.Sprintf("Sending new user notification for user %v", u.Username))
|
||||||
comm.(UserEvents).OnNewUser(u)
|
comm.(UserEvents).OnNewUser(u)
|
||||||
|
@ -142,7 +142,7 @@ func OnNewUser(u *users.User) {
|
||||||
|
|
||||||
// OnUpdatedUser is triggered when a new user is updated - UserEvents interface
|
// OnUpdatedUser is triggered when a new user is updated - UserEvents interface
|
||||||
func OnUpdatedUser(u *users.User) {
|
func OnUpdatedUser(u *users.User) {
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
if utils.IsType(comm, new(UserEvents)) && isEnabled(comm) && inLimits(comm) {
|
if utils.IsType(comm, new(UserEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||||
log.Debugln(fmt.Sprintf("Sending updated user notification for user %v", u.Username))
|
log.Debugln(fmt.Sprintf("Sending updated user notification for user %v", u.Username))
|
||||||
comm.(UserEvents).OnUpdatedUser(u)
|
comm.(UserEvents).OnUpdatedUser(u)
|
||||||
|
@ -153,7 +153,7 @@ func OnUpdatedUser(u *users.User) {
|
||||||
|
|
||||||
// OnDeletedUser is triggered when a new user is deleted - UserEvents interface
|
// OnDeletedUser is triggered when a new user is deleted - UserEvents interface
|
||||||
func OnDeletedUser(u *users.User) {
|
func OnDeletedUser(u *users.User) {
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
if utils.IsType(comm, new(UserEvents)) && isEnabled(comm) && inLimits(comm) {
|
if utils.IsType(comm, new(UserEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||||
log.Debugln(fmt.Sprintf("Sending deleted user notification for user %v", u.Username))
|
log.Debugln(fmt.Sprintf("Sending deleted user notification for user %v", u.Username))
|
||||||
comm.(UserEvents).OnDeletedUser(u)
|
comm.(UserEvents).OnDeletedUser(u)
|
||||||
|
@ -164,7 +164,7 @@ func OnDeletedUser(u *users.User) {
|
||||||
|
|
||||||
//// OnUpdatedCore is triggered when the CoreApp settings are saved - CoreEvents interface
|
//// OnUpdatedCore is triggered when the CoreApp settings are saved - CoreEvents interface
|
||||||
//func OnUpdatedCore(c *core.Core) {
|
//func OnUpdatedCore(c *core.Core) {
|
||||||
// for _, comm := range AllCommunications {
|
// for _, comm := range allNotifiers {
|
||||||
// if utils.IsType(comm, new(CoreEvents)) && isEnabled(comm) && inLimits(comm) {
|
// if utils.IsType(comm, new(CoreEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||||
// log.Debugln(fmt.Sprintf("Sending updated core notification"))
|
// log.Debugln(fmt.Sprintf("Sending updated core notification"))
|
||||||
// comm.(CoreEvents).OnUpdatedCore(c)
|
// comm.(CoreEvents).OnUpdatedCore(c)
|
||||||
|
@ -174,7 +174,7 @@ func OnDeletedUser(u *users.User) {
|
||||||
//
|
//
|
||||||
//// OnStart is triggered when the Statping service has started
|
//// OnStart is triggered when the Statping service has started
|
||||||
//func OnStart(c *core.Core) {
|
//func OnStart(c *core.Core) {
|
||||||
// for _, comm := range AllCommunications {
|
// for _, comm := range allNotifiers {
|
||||||
// if utils.IsType(comm, new(CoreEvents)) && isEnabled(comm) && inLimits(comm) {
|
// if utils.IsType(comm, new(CoreEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||||
// comm.(CoreEvents).OnUpdatedCore(c)
|
// comm.(CoreEvents).OnUpdatedCore(c)
|
||||||
// }
|
// }
|
||||||
|
@ -183,7 +183,7 @@ func OnDeletedUser(u *users.User) {
|
||||||
|
|
||||||
// OnNewNotifier is triggered when a new notifier is loaded
|
// OnNewNotifier is triggered when a new notifier is loaded
|
||||||
func OnNewNotifier(n *Notification) {
|
func OnNewNotifier(n *Notification) {
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
if utils.IsType(comm, new(NotifierEvents)) && isEnabled(comm) && inLimits(comm) {
|
if utils.IsType(comm, new(NotifierEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||||
comm.(NotifierEvents).OnNewNotifier(n)
|
comm.(NotifierEvents).OnNewNotifier(n)
|
||||||
comm.Select().Hits.OnNewNotifier++
|
comm.Select().Hits.OnNewNotifier++
|
||||||
|
@ -193,7 +193,7 @@ func OnNewNotifier(n *Notification) {
|
||||||
|
|
||||||
// OnUpdatedNotifier is triggered when a notifier has been updated
|
// OnUpdatedNotifier is triggered when a notifier has been updated
|
||||||
func OnUpdatedNotifier(n *Notification) {
|
func OnUpdatedNotifier(n *Notification) {
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
if utils.IsType(comm, new(NotifierEvents)) && isEnabled(comm) && inLimits(comm) {
|
if utils.IsType(comm, new(NotifierEvents)) && isEnabled(comm) && inLimits(comm) {
|
||||||
log.Infoln(fmt.Sprintf("Sending updated notifier for %v", n.Id))
|
log.Infoln(fmt.Sprintf("Sending updated notifier for %v", n.Id))
|
||||||
comm.(NotifierEvents).OnUpdatedNotifier(n)
|
comm.(NotifierEvents).OnUpdatedNotifier(n)
|
||||||
|
|
|
@ -1,179 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 notifications
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/hunterlong/statping/source"
|
|
||||||
"github.com/hunterlong/statping/types/failures"
|
|
||||||
"github.com/hunterlong/statping/types/services"
|
|
||||||
"github.com/hunterlong/statping/types/users"
|
|
||||||
"github.com/hunterlong/statping/utils"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ExampleNotifier is an example on how to use the Statping notifier struct
|
|
||||||
type ExampleNotifier struct {
|
|
||||||
*Notification
|
|
||||||
}
|
|
||||||
|
|
||||||
// example is a example variable for a example notifier
|
|
||||||
var example = &ExampleNotifier{&Notification{
|
|
||||||
Method: METHOD,
|
|
||||||
Host: "http://exmaplehost.com",
|
|
||||||
Title: "Example",
|
|
||||||
Description: "Example Notifier",
|
|
||||||
Author: "Hunter Long",
|
|
||||||
AuthorUrl: "https://github.com/hunterlong",
|
|
||||||
Delay: time.Duration(3 * time.Second),
|
|
||||||
Limits: 7,
|
|
||||||
Form: []NotificationForm{{
|
|
||||||
Type: "text",
|
|
||||||
Title: "Host",
|
|
||||||
Placeholder: "Insert your Host here.",
|
|
||||||
DbField: "host",
|
|
||||||
SmallText: "this is where you would put the 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",
|
|
||||||
}},
|
|
||||||
}}
|
|
||||||
|
|
||||||
// init will be ran when Statping is loaded, AddNotifier will add the notifier instance to the system
|
|
||||||
func init() {
|
|
||||||
dir = utils.Directory
|
|
||||||
source.Assets()
|
|
||||||
utils.InitLogs()
|
|
||||||
injectDatabase()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send is the main function to hold your notifier functionality
|
|
||||||
func (n *ExampleNotifier) Send(msg interface{}) error {
|
|
||||||
message := msg.(string)
|
|
||||||
fmt.Printf("i received this string: %v\n", message)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select is a required basic event for the Notifier interface
|
|
||||||
func (n *ExampleNotifier) Select() *Notification {
|
|
||||||
return n.Notification
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnSave is a required basic event for the Notifier interface
|
|
||||||
func (n *ExampleNotifier) OnSave() error {
|
|
||||||
msg := fmt.Sprintf("received on save trigger")
|
|
||||||
n.AddQueue("onsave", msg)
|
|
||||||
return errors.New("onsave triggered")
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnSuccess is a required basic event for the Notifier interface
|
|
||||||
func (n *ExampleNotifier) OnSuccess(s *services.Service) {
|
|
||||||
msg := fmt.Sprintf("received a count trigger for service: %v\n", s.Name)
|
|
||||||
n.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnFailure is a required basic event for the Notifier interface
|
|
||||||
func (n *ExampleNotifier) OnFailure(s *services.Service, f *failures.Failure) {
|
|
||||||
msg := fmt.Sprintf("received a failure trigger for service: %v\n", s.Name)
|
|
||||||
n.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnTest is a option testing event for the Notifier interface
|
|
||||||
func (n *ExampleNotifier) OnTest() error {
|
|
||||||
fmt.Printf("received a test trigger with form data: %v\n", n.Host)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnNewService is a option event for new services
|
|
||||||
func (n *ExampleNotifier) OnNewService(s *services.Service) {
|
|
||||||
msg := fmt.Sprintf("received a new service trigger for service: %v\n", s.Name)
|
|
||||||
n.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnUpdatedService is a option event for updated services
|
|
||||||
func (n *ExampleNotifier) OnUpdatedService(s *services.Service) {
|
|
||||||
msg := fmt.Sprintf("received a update service trigger for service: %v\n", s.Name)
|
|
||||||
n.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnDeletedService is a option event for deleted services
|
|
||||||
func (n *ExampleNotifier) OnDeletedService(s *services.Service) {
|
|
||||||
msg := fmt.Sprintf("received a delete service trigger for service: %v\n", s.Name)
|
|
||||||
n.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnNewUser is a option event for new users
|
|
||||||
func (n *ExampleNotifier) OnNewUser(s *users.User) {
|
|
||||||
msg := fmt.Sprintf("received a new user trigger for user: %v\n", s.Username)
|
|
||||||
n.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnUpdatedUser is a option event for updated users
|
|
||||||
func (n *ExampleNotifier) OnUpdatedUser(s *users.User) {
|
|
||||||
msg := fmt.Sprintf("received a updated user trigger for user: %v\n", s.Username)
|
|
||||||
n.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnDeletedUser is a option event for deleted users
|
|
||||||
func (n *ExampleNotifier) OnDeletedUser(s *users.User) {
|
|
||||||
msg := fmt.Sprintf("received a deleted user trigger for user: %v\n", s.Username)
|
|
||||||
n.AddQueue(fmt.Sprintf("service_%v", s.Id), msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnNewNotifier is triggered when a new notifier has initialized
|
|
||||||
func (n *ExampleNotifier) OnNewNotifier(s *Notification) {
|
|
||||||
msg := fmt.Sprintf("received a new notifier trigger for notifier: %v\n", s.Method)
|
|
||||||
n.AddQueue(fmt.Sprintf("notifier_%v", s.Id), msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnUpdatedNotifier is triggered when a notifier has been updated
|
|
||||||
func (n *ExampleNotifier) OnUpdatedNotifier(s *Notification) {
|
|
||||||
msg := fmt.Sprintf("received a update notifier trigger for notifier: %v\n", s.Method)
|
|
||||||
n.AddQueue(fmt.Sprintf("notifier_%v", s.Id), msg)
|
|
||||||
}
|
|
|
@ -3,7 +3,6 @@ package notifications
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hunterlong/statping/utils"
|
"github.com/hunterlong/statping/utils"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -96,30 +95,35 @@ func (n *Notification) GetValue(dbField string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init accepts the Notifier interface to initialize the notifier
|
// Init accepts the Notifier interface to initialize the notifier
|
||||||
func Init(n Notifier) (*Notification, error) {
|
//func Init(n Notifier) (*Notification, error) {
|
||||||
err := install(n)
|
// if Exists(n.Select().Method) {
|
||||||
if err == nil {
|
// AllCommunications = append(AllCommunications, n)
|
||||||
notify, err := SelectNotification(n)
|
// } else {
|
||||||
if err != nil {
|
// _, err := insertDatabase(n)
|
||||||
return nil, errors.Wrap(err, "error selecting notification")
|
// if err != nil {
|
||||||
}
|
// log.Errorln(err)
|
||||||
|
// return nil, err
|
||||||
notify.CreatedAt = time.Now().UTC()
|
// }
|
||||||
notify.UpdatedAt = time.Now().UTC()
|
// AllCommunications = append(AllCommunications, n)
|
||||||
if notify.Delay.Seconds() == 0 {
|
// }
|
||||||
notify.Delay = 1 * time.Second
|
//
|
||||||
}
|
// notify, err := SelectNotification(n)
|
||||||
notify.testable = utils.IsType(n, new(Tester))
|
// if err != nil {
|
||||||
notify.Form = n.Select().Form
|
// return nil, errors.Wrap(err, "error selecting notification")
|
||||||
|
// }
|
||||||
AllCommunications = append(AllCommunications, n)
|
//
|
||||||
|
// notify.CreatedAt = time.Now().UTC()
|
||||||
} else {
|
// notify.UpdatedAt = time.Now().UTC()
|
||||||
return nil, errors.Wrap(err, "error installing notification")
|
// if notify.Delay.Seconds() == 0 {
|
||||||
}
|
// notify.Delay = 1 * time.Second
|
||||||
|
// }
|
||||||
return nil, err
|
// notify.testable = utils.IsType(n, new(Tester))
|
||||||
}
|
// notify.Form = n.Select().Form
|
||||||
|
//
|
||||||
|
// AllCommunications = append(AllCommunications, n)
|
||||||
|
//
|
||||||
|
// return nil, err
|
||||||
|
//}
|
||||||
|
|
||||||
// ResetQueue will clear the notifiers Queue
|
// ResetQueue will clear the notifiers Queue
|
||||||
func (n *Notification) ResetQueue() {
|
func (n *Notification) ResetQueue() {
|
||||||
|
|
|
@ -19,7 +19,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hunterlong/statping/database"
|
|
||||||
"github.com/hunterlong/statping/types/null"
|
"github.com/hunterlong/statping/types/null"
|
||||||
"github.com/hunterlong/statping/types/services"
|
"github.com/hunterlong/statping/types/services"
|
||||||
"github.com/hunterlong/statping/utils"
|
"github.com/hunterlong/statping/utils"
|
||||||
|
@ -29,16 +28,14 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// db holds the Statping database connection
|
// db holds the Statping database connection
|
||||||
db database.Database
|
|
||||||
log = utils.Log.WithField("type", "notifier")
|
log = utils.Log.WithField("type", "notifier")
|
||||||
AllCommunications []Notifier
|
allNotifiers []Notifier
|
||||||
)
|
)
|
||||||
|
|
||||||
// Notification contains all the fields for a Statping Notifier.
|
// Notification contains all the fields for a Statping Notifier.
|
||||||
type Notification struct {
|
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"`
|
Method string `gorm:"column:method" json:"method"`
|
||||||
name string `gorm:"column:name" json:"name"`
|
|
||||||
Host string `gorm:"not null;column:host" json:"host,omitempty"`
|
Host string `gorm:"not null;column:host" json:"host,omitempty"`
|
||||||
Port int `gorm:"not null;column:port" json:"port,omitempty"`
|
Port int `gorm:"not null;column:port" json:"port,omitempty"`
|
||||||
Username string `gorm:"not null;column:username" json:"username,omitempty"`
|
Username string `gorm:"not null;column:username" json:"username,omitempty"`
|
||||||
|
@ -108,16 +105,6 @@ type NotificationLog struct {
|
||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDB is called by core to inject the database for a notifier to use
|
|
||||||
func SetDB(d database.Database) {
|
|
||||||
db = d
|
|
||||||
}
|
|
||||||
|
|
||||||
// asNotification accepts a Notifier and returns a Notification struct
|
|
||||||
func asNotification(n Notifier) *Notification {
|
|
||||||
return n.Select()
|
|
||||||
}
|
|
||||||
|
|
||||||
// normalizeType will accept multiple interfaces and converts it into a string for logging
|
// normalizeType will accept multiple interfaces and converts it into a string for logging
|
||||||
func normalizeType(ty interface{}) string {
|
func normalizeType(ty interface{}) string {
|
||||||
switch v := ty.(type) {
|
switch v := ty.(type) {
|
||||||
|
@ -169,20 +156,9 @@ func SelectNotification(n Notifier) (*Notification, error) {
|
||||||
return notifier, err.Error()
|
return notifier, err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
// insertDatabase will create a new record into the database for the notifier
|
|
||||||
func insertDatabase(n Notifier) (int64, error) {
|
|
||||||
noti := n.Select()
|
|
||||||
noti.Limits = 3
|
|
||||||
noti.name = noti.Name()
|
|
||||||
if err := noti.Create(); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return noti.Id, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectNotifier returns the Notification struct from the database
|
// SelectNotifier returns the Notification struct from the database
|
||||||
func SelectNotifier(method string) (*Notification, Notifier, error) {
|
func SelectNotifier(method string) (*Notification, Notifier, error) {
|
||||||
for _, comm := range AllCommunications {
|
for _, comm := range allNotifiers {
|
||||||
n, ok := comm.(Notifier)
|
n, ok := comm.(Notifier)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil, fmt.Errorf("incorrect notification type: %v", reflect.TypeOf(n).String())
|
return nil, nil, fmt.Errorf("incorrect notification type: %v", reflect.TypeOf(n).String())
|
||||||
|
@ -231,20 +207,22 @@ CheckNotifier:
|
||||||
}
|
}
|
||||||
|
|
||||||
// install will check the database for the notification, if its not inserted it will insert a new record for it
|
// 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 {
|
//func install(n Notifier) error {
|
||||||
_, err := insertDatabase(n)
|
// log.WithFields(utils.ToFields(n)).
|
||||||
if err != nil {
|
// Debugln(fmt.Sprintf("Checking if notifier '%v' is installed", n.Select().Method))
|
||||||
log.Errorln(err)
|
//
|
||||||
return err
|
// if Exists(n.Select().Method) {
|
||||||
}
|
// AllCommunications = append(AllCommunications, n)
|
||||||
|
// } else {
|
||||||
AllCommunications = append(AllCommunications, n)
|
// _, err := insertDatabase(n)
|
||||||
|
// if err != nil {
|
||||||
log.WithFields(utils.ToFields(n)).
|
// log.Errorln(err)
|
||||||
Debugln(fmt.Sprintf("Checking if notifier '%v' is installed", n.Select().Method))
|
// return err
|
||||||
|
// }
|
||||||
return nil
|
// AllCommunications = append(AllCommunications, n)
|
||||||
}
|
// }
|
||||||
|
// return nil
|
||||||
|
//}
|
||||||
|
|
||||||
// isEnabled returns true if the notifier is enabled
|
// isEnabled returns true if the notifier is enabled
|
||||||
func isEnabled(n interface{}) bool {
|
func isEnabled(n interface{}) bool {
|
||||||
|
|
|
@ -1,212 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 notifications
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"github.com/hunterlong/statping/database"
|
|
||||||
"github.com/hunterlong/statping/types/failures"
|
|
||||||
"github.com/hunterlong/statping/types/null"
|
|
||||||
"github.com/hunterlong/statping/types/services"
|
|
||||||
"github.com/hunterlong/statping/types/users"
|
|
||||||
"github.com/hunterlong/statping/utils"
|
|
||||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
dir string
|
|
||||||
METHOD = "example"
|
|
||||||
)
|
|
||||||
|
|
||||||
var service = &services.Service{
|
|
||||||
Name: "Interpol - All The Rage Back Home",
|
|
||||||
Domain: "https://www.youtube.com/watch?v=-u6DvRyyKGU",
|
|
||||||
ExpectedStatus: 200,
|
|
||||||
Interval: 30,
|
|
||||||
Type: "http",
|
|
||||||
Method: "GET",
|
|
||||||
Timeout: 20,
|
|
||||||
AllowNotifications: null.NewNullBool(true),
|
|
||||||
}
|
|
||||||
|
|
||||||
var failure = &failures.Failure{
|
|
||||||
Issue: "testing",
|
|
||||||
}
|
|
||||||
|
|
||||||
var user = &users.User{
|
|
||||||
Username: "admin",
|
|
||||||
Email: "info@email.com",
|
|
||||||
}
|
|
||||||
|
|
||||||
func injectDatabase() {
|
|
||||||
sqlPath := dir + "/notifier.db"
|
|
||||||
utils.DeleteFile(sqlPath)
|
|
||||||
db, _ = database.Openw("sqlite3", sqlPath)
|
|
||||||
db.CreateTable(&Notification{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsBasicType(t *testing.T) {
|
|
||||||
assert.True(t, utils.IsType(example, new(Notifier)))
|
|
||||||
assert.True(t, utils.IsType(example, new(BasicEvents)))
|
|
||||||
assert.True(t, utils.IsType(example, new(ServiceEvents)))
|
|
||||||
assert.True(t, utils.IsType(example, new(UserEvents)))
|
|
||||||
assert.True(t, utils.IsType(example, new(NotifierEvents)))
|
|
||||||
assert.True(t, utils.IsType(example, new(Tester)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectNotification(t *testing.T) {
|
|
||||||
notifier, notif, err := SelectNotifier(example.Method)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.NotNil(t, notifier)
|
|
||||||
assert.NotNil(t, notif)
|
|
||||||
assert.Equal(t, "example", notifier.Method)
|
|
||||||
assert.False(t, notifier.Enabled.Bool)
|
|
||||||
assert.False(t, notifier.IsRunning())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddQueue(t *testing.T) {
|
|
||||||
msg := "this is a test in the queue!"
|
|
||||||
example.AddQueue(fmt.Sprintf("service_%v", 0), msg)
|
|
||||||
assert.Equal(t, 1, len(example.Queue))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNotification_Update(t *testing.T) {
|
|
||||||
notifier, err := SelectNotification(example)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
notifier.Host = "http://demo.statping.com/api"
|
|
||||||
notifier.Port = 9090
|
|
||||||
notifier.Username = "admin"
|
|
||||||
notifier.Password = "password123"
|
|
||||||
notifier.Var1 = "var1_is_here"
|
|
||||||
notifier.Var2 = "var2_is_here"
|
|
||||||
notifier.ApiKey = "USBdu82HDiiuw9327yGYDGw"
|
|
||||||
notifier.ApiSecret = "PQopncow929hUIDHGwiud"
|
|
||||||
notifier.Limits = 10
|
|
||||||
err = notifier.Update()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
selected, err := SelectNotification(example)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "http://demo.statping.com/api", selected.GetValue("host"))
|
|
||||||
assert.Equal(t, "http://demo.statping.com/api", example.Notification.Host)
|
|
||||||
assert.Equal(t, "http://demo.statping.com/api", example.Host)
|
|
||||||
assert.Equal(t, "USBdu82HDiiuw9327yGYDGw", selected.GetValue("api_key"))
|
|
||||||
assert.Equal(t, "USBdu82HDiiuw9327yGYDGw", example.ApiKey)
|
|
||||||
assert.False(t, selected.Enabled.Bool)
|
|
||||||
assert.False(t, selected.IsRunning())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEnableNotification(t *testing.T) {
|
|
||||||
notifier, err := SelectNotification(example)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
notifier.Enabled = null.NewNullBool(true)
|
|
||||||
err = notifier.Update()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.True(t, notifier.Enabled.Bool)
|
|
||||||
assert.True(t, notifier.IsRunning())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsEnabled(t *testing.T) {
|
|
||||||
assert.True(t, isEnabled(example))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsRunning(t *testing.T) {
|
|
||||||
assert.True(t, example.IsRunning())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLastSent(t *testing.T) {
|
|
||||||
notifier, err := SelectNotification(example)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "0s", notifier.LastSent().String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithinLimits(t *testing.T) {
|
|
||||||
notifier, err := SelectNotification(example)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, 10, notifier.Limits)
|
|
||||||
assert.True(t, inLimits(example))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNotification_GetValue(t *testing.T) {
|
|
||||||
notifier, err := SelectNotification(example)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
val := notifier.GetValue("Host")
|
|
||||||
assert.Equal(t, "http://demo.statping.com/api", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOnSave(t *testing.T) {
|
|
||||||
err := example.OnSave()
|
|
||||||
assert.Equal(t, "onsave triggered", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOnSuccess(t *testing.T) {
|
|
||||||
OnSuccess(service)
|
|
||||||
assert.Equal(t, 2, len(example.Queue))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOnFailure(t *testing.T) {
|
|
||||||
OnFailure(service, failure)
|
|
||||||
assert.Equal(t, 3, len(example.Queue))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOnNewService(t *testing.T) {
|
|
||||||
OnNewService(service)
|
|
||||||
assert.Equal(t, 4, len(example.Queue))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOnUpdatedService(t *testing.T) {
|
|
||||||
OnUpdatedService(service)
|
|
||||||
assert.Equal(t, 5, len(example.Queue))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOnDeletedService(t *testing.T) {
|
|
||||||
OnDeletedService(service)
|
|
||||||
assert.Equal(t, 6, len(example.Queue))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOnNewUser(t *testing.T) {
|
|
||||||
OnNewUser(user)
|
|
||||||
assert.Equal(t, 7, len(example.Queue))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOnUpdatedUser(t *testing.T) {
|
|
||||||
OnUpdatedUser(user)
|
|
||||||
assert.Equal(t, 8, len(example.Queue))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOnDeletedUser(t *testing.T) {
|
|
||||||
OnDeletedUser(user)
|
|
||||||
assert.Equal(t, 9, len(example.Queue))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOnUpdatedNotifier(t *testing.T) {
|
|
||||||
OnUpdatedNotifier(example.Select())
|
|
||||||
assert.Equal(t, 11, len(example.Queue))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunAllQueueAndStop(t *testing.T) {
|
|
||||||
assert.True(t, example.IsRunning())
|
|
||||||
assert.Equal(t, 11, len(example.Queue))
|
|
||||||
go Queue(example)
|
|
||||||
time.Sleep(13 * time.Second)
|
|
||||||
assert.NotZero(t, len(example.Queue))
|
|
||||||
example.Close()
|
|
||||||
assert.False(t, example.IsRunning())
|
|
||||||
assert.NotZero(t, len(example.Queue))
|
|
||||||
}
|
|
|
@ -48,8 +48,6 @@ func (s *Service) Create() error {
|
||||||
return err.Error()
|
return err.Error()
|
||||||
}
|
}
|
||||||
allServices[s.Id] = s
|
allServices[s.Id] = s
|
||||||
|
|
||||||
go ServiceCheckQueue(allServices[s.Id], true)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Samples() {
|
func Samples() error {
|
||||||
createdOn := time.Now().Add(((-24 * 30) * 3) * time.Hour).UTC()
|
createdOn := time.Now().Add(((-24 * 30) * 3) * time.Hour).UTC()
|
||||||
s1 := &Service{
|
s1 := &Service{
|
||||||
Name: "Google",
|
Name: "Google",
|
||||||
|
@ -21,7 +21,9 @@ func Samples() {
|
||||||
VerifySSL: null.NewNullBool(true),
|
VerifySSL: null.NewNullBool(true),
|
||||||
CreatedAt: createdOn,
|
CreatedAt: createdOn,
|
||||||
}
|
}
|
||||||
s1.Create()
|
if err := s1.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
s2 := &Service{
|
s2 := &Service{
|
||||||
Name: "Statping Github",
|
Name: "Statping Github",
|
||||||
|
@ -36,7 +38,9 @@ func Samples() {
|
||||||
VerifySSL: null.NewNullBool(true),
|
VerifySSL: null.NewNullBool(true),
|
||||||
CreatedAt: createdOn,
|
CreatedAt: createdOn,
|
||||||
}
|
}
|
||||||
s2.Create()
|
if err := s2.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
s3 := &Service{
|
s3 := &Service{
|
||||||
Name: "JSON Users Test",
|
Name: "JSON Users Test",
|
||||||
|
@ -52,7 +56,9 @@ func Samples() {
|
||||||
GroupId: 2,
|
GroupId: 2,
|
||||||
CreatedAt: createdOn,
|
CreatedAt: createdOn,
|
||||||
}
|
}
|
||||||
s3.Create()
|
if err := s3.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
s4 := &Service{
|
s4 := &Service{
|
||||||
Name: "JSON API Tester",
|
Name: "JSON API Tester",
|
||||||
|
@ -70,7 +76,9 @@ func Samples() {
|
||||||
GroupId: 2,
|
GroupId: 2,
|
||||||
CreatedAt: createdOn,
|
CreatedAt: createdOn,
|
||||||
}
|
}
|
||||||
s4.Create()
|
if err := s4.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
s5 := &Service{
|
s5 := &Service{
|
||||||
Name: "Google DNS",
|
Name: "Google DNS",
|
||||||
|
@ -84,5 +92,9 @@ func Samples() {
|
||||||
GroupId: 1,
|
GroupId: 1,
|
||||||
CreatedAt: createdOn,
|
CreatedAt: createdOn,
|
||||||
}
|
}
|
||||||
s5.Create()
|
if err := s5.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,107 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hunterlong/statping/types/checkins"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
testCheckin *checkins.Checkin
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCreateCheckin(t *testing.T) {
|
|
||||||
service, err := Find(2)
|
|
||||||
require.Nil(t, err)
|
|
||||||
checkin := &checkins.Checkin{
|
|
||||||
ServiceId: service.Id,
|
|
||||||
Interval: 10,
|
|
||||||
GracePeriod: 5,
|
|
||||||
}
|
|
||||||
err = checkin.Create()
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.NotZero(t, checkin.Id)
|
|
||||||
assert.NotEmpty(t, testCheckin.ApiKey)
|
|
||||||
assert.Equal(t, int64(10), testCheckin.Interval)
|
|
||||||
assert.Equal(t, int64(5), testCheckin.GracePeriod)
|
|
||||||
assert.True(t, testCheckin.Expected().Minutes() < 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectCheckin(t *testing.T) {
|
|
||||||
service, err := Find(2)
|
|
||||||
require.Nil(t, err)
|
|
||||||
chks := service.Checkins()
|
|
||||||
assert.NotNil(t, chks)
|
|
||||||
assert.Equal(t, 1, len(chks))
|
|
||||||
c := chks[0]
|
|
||||||
assert.Equal(t, int64(10), c.Interval)
|
|
||||||
assert.Equal(t, int64(5), c.GracePeriod)
|
|
||||||
assert.Equal(t, 7, len(c.ApiKey))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateCheckin(t *testing.T) {
|
|
||||||
testCheckin.Interval = 60
|
|
||||||
testCheckin.GracePeriod = 15
|
|
||||||
err := testCheckin.Update()
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.NotZero(t, testCheckin.Id)
|
|
||||||
assert.NotEmpty(t, testCheckin.ApiKey)
|
|
||||||
|
|
||||||
service, err := Find(1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
checkin := service.Checkins()[0]
|
|
||||||
assert.Equal(t, int64(60), checkin.Interval)
|
|
||||||
assert.Equal(t, int64(15), checkin.GracePeriod)
|
|
||||||
t.Log(testCheckin.Expected())
|
|
||||||
assert.True(t, testCheckin.Expected().Minutes() < 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateCheckinHits(t *testing.T) {
|
|
||||||
service, err := Find(1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
check := service.Checkins()
|
|
||||||
assert.Equal(t, 1, len(check))
|
|
||||||
created := time.Now().UTC().Add(-60 * time.Second)
|
|
||||||
hit := &checkins.CheckinHit{
|
|
||||||
Checkin: testCheckin.Id,
|
|
||||||
From: "192.168.1.1",
|
|
||||||
CreatedAt: created,
|
|
||||||
}
|
|
||||||
err = hit.Create()
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
checks := service.Checkins()
|
|
||||||
assert.Equal(t, 1, len(checks))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectCheckinMethods(t *testing.T) {
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
service, err := Find(1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
checkins := service.Checkins()
|
|
||||||
assert.NotNil(t, checkins)
|
|
||||||
assert.Equal(t, float64(60), testCheckin.Period().Seconds())
|
|
||||||
assert.Equal(t, float64(15), testCheckin.Grace().Seconds())
|
|
||||||
t.Log(testCheckin.Expected())
|
|
||||||
|
|
||||||
lastHit := checkins[0]
|
|
||||||
assert.True(t, testCheckin.Expected().Seconds() < -5)
|
|
||||||
assert.False(t, lastHit.CreatedAt.IsZero())
|
|
||||||
}
|
|
|
@ -1,332 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hunterlong/statping/types/failures"
|
|
||||||
"github.com/hunterlong/statping/utils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
newServiceId int64
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSelectHTTPService(t *testing.T) {
|
|
||||||
services, err := SelectAllServices(false)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, 15, len(services))
|
|
||||||
assert.Equal(t, "Google", services[0].Name)
|
|
||||||
assert.Equal(t, "http", services[0].Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectAllServices(t *testing.T) {
|
|
||||||
services := All()
|
|
||||||
for _, s := range services {
|
|
||||||
s.CheckService(false)
|
|
||||||
assert.False(t, s.IsRunning())
|
|
||||||
t.Logf("ID: %v %v\n", s.Id, s.Name)
|
|
||||||
}
|
|
||||||
assert.Equal(t, 15, len(services))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServiceDowntime(t *testing.T) {
|
|
||||||
service, err := Find(15)
|
|
||||||
require.Nil(t, err)
|
|
||||||
downtime := service.Downtime()
|
|
||||||
assert.True(t, downtime.Seconds() > 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectTCPService(t *testing.T) {
|
|
||||||
services := All()
|
|
||||||
assert.Equal(t, 15, len(services))
|
|
||||||
service, err := Find(5)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.NotNil(t, service)
|
|
||||||
assert.Equal(t, "Google DNS", service.Name)
|
|
||||||
assert.Equal(t, "tcp", service.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateService(t *testing.T) {
|
|
||||||
service, err := Find(1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, "Google", service.Name)
|
|
||||||
service.Name = "Updated Google"
|
|
||||||
service.Interval = 5
|
|
||||||
|
|
||||||
err = service.Update()
|
|
||||||
require.Nil(t, err)
|
|
||||||
|
|
||||||
// check if updating pointer array shutdown any other service
|
|
||||||
service, err = Find(1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, "Updated Google", service.Name)
|
|
||||||
assert.Equal(t, 5, service.Interval)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateAllServices(t *testing.T) {
|
|
||||||
services, err := SelectAllServices(false)
|
|
||||||
require.Nil(t, err)
|
|
||||||
var i int
|
|
||||||
for _, srv := range services {
|
|
||||||
srv.Name = "Changed " + srv.Name
|
|
||||||
srv.Interval = i + 3
|
|
||||||
|
|
||||||
err := srv.Update()
|
|
||||||
require.Nil(t, err)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServiceHTTPCheck(t *testing.T) {
|
|
||||||
service, err := Find(1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
service.CheckService(true)
|
|
||||||
assert.Equal(t, "Changed Updated Google", service.Name)
|
|
||||||
assert.True(t, service.Online)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckHTTPService(t *testing.T) {
|
|
||||||
service, err := Find(1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, "Changed Updated Google", service.Name)
|
|
||||||
assert.True(t, service.Online)
|
|
||||||
assert.Equal(t, 200, service.LastStatusCode)
|
|
||||||
assert.NotZero(t, service.Latency)
|
|
||||||
assert.NotZero(t, service.PingTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServiceTCPCheck(t *testing.T) {
|
|
||||||
service, err := Find(5)
|
|
||||||
require.Nil(t, err)
|
|
||||||
service.CheckService(false)
|
|
||||||
assert.Equal(t, "Changed Google DNS", service.Name)
|
|
||||||
assert.True(t, service.Online)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckTCPService(t *testing.T) {
|
|
||||||
service, err := Find(5)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, "Changed Google DNS", service.Name)
|
|
||||||
assert.True(t, service.Online)
|
|
||||||
assert.NotZero(t, service.Latency)
|
|
||||||
assert.NotZero(t, service.PingTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServiceOnline24Hours(t *testing.T) {
|
|
||||||
since := utils.Now().Add(-24 * time.Hour).Add(-10 * time.Minute)
|
|
||||||
service, err := Find(1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, float32(100), service.OnlineSince(since))
|
|
||||||
service2, err := Find(5)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, float32(100), service2.OnlineSince(since))
|
|
||||||
service3, err := Find(14)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.True(t, service3.OnlineSince(since) > float32(49))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServiceAvgUptime(t *testing.T) {
|
|
||||||
since := utils.Now().Add(-24 * time.Hour).Add(-10 * time.Minute)
|
|
||||||
service, err := Find(1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.NotEqual(t, "0.00", service.AvgTime())
|
|
||||||
service2, err := Find(5)
|
|
||||||
assert.Equal(t, "100", service2.AvgTime())
|
|
||||||
service3, err := Find(13)
|
|
||||||
assert.NotEqual(t, "0", service3.HitsSince(since).Avg())
|
|
||||||
service4, err := Find(15)
|
|
||||||
assert.NotEqual(t, "0", service4.HitsSince(since).Avg())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateService(t *testing.T) {
|
|
||||||
s := &Service{
|
|
||||||
Name: "That'll do 🐢",
|
|
||||||
Domain: "https://www.youtube.com/watch?v=rjQtzV9IZ0Q",
|
|
||||||
ExpectedStatus: 200,
|
|
||||||
Interval: 3,
|
|
||||||
Type: "http",
|
|
||||||
Method: "GET",
|
|
||||||
Timeout: 20,
|
|
||||||
GroupId: 1,
|
|
||||||
}
|
|
||||||
err := s.Create()
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.NotZero(t, s.Id)
|
|
||||||
newService, err := Find(s.Id)
|
|
||||||
assert.Equal(t, "That'll do 🐢", newService.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestViewNewService(t *testing.T) {
|
|
||||||
newService, err := Find(newServiceId)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, "That'll do 🐢", newService.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateFailingHTTPService(t *testing.T) {
|
|
||||||
s := &Service{
|
|
||||||
Name: "Bad URL",
|
|
||||||
Domain: "http://localhost/iamnothere",
|
|
||||||
ExpectedStatus: 200,
|
|
||||||
Interval: 2,
|
|
||||||
Type: "http",
|
|
||||||
Method: "GET",
|
|
||||||
Timeout: 5,
|
|
||||||
GroupId: 1,
|
|
||||||
}
|
|
||||||
err := s.Create()
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.NotZero(t, s.Id)
|
|
||||||
newService, err := Find(s.Id)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, "Bad URL", newService.Name)
|
|
||||||
t.Log("new service ID: ", newServiceId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServiceFailedCheck(t *testing.T) {
|
|
||||||
service, err := Find(17)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, "Bad URL", service.Name)
|
|
||||||
service.CheckService(false)
|
|
||||||
assert.Equal(t, "Bad URL", service.Name)
|
|
||||||
assert.False(t, service.Online)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateFailingTCPService(t *testing.T) {
|
|
||||||
s := &Service{
|
|
||||||
Name: "Bad TCP",
|
|
||||||
Domain: "localhost",
|
|
||||||
Port: 5050,
|
|
||||||
Interval: 30,
|
|
||||||
Type: "tcp",
|
|
||||||
Timeout: 5,
|
|
||||||
GroupId: 1,
|
|
||||||
}
|
|
||||||
err := s.Create()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.NotZero(t, s.Id)
|
|
||||||
newService, err := Find(s.Id)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, "Bad TCP", newService.Name)
|
|
||||||
t.Log("new failing tcp service ID: ", newServiceId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServiceFailedTCPCheck(t *testing.T) {
|
|
||||||
srv, err := Find(newServiceId)
|
|
||||||
require.Nil(t, err)
|
|
||||||
srv.CheckService(false)
|
|
||||||
assert.Equal(t, "Bad TCP", srv.Name)
|
|
||||||
assert.False(t, srv.Online)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateServiceFailure(t *testing.T) {
|
|
||||||
service, err := Find(8)
|
|
||||||
fail := &failures.Failure{
|
|
||||||
Issue: "This is not an issue, but it would container HTTP response errors.",
|
|
||||||
Method: "http",
|
|
||||||
Service: service.Id,
|
|
||||||
}
|
|
||||||
err = fail.Create()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.NotZero(t, fail.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteService(t *testing.T) {
|
|
||||||
service, err := Find(newServiceId)
|
|
||||||
|
|
||||||
count, err := SelectAllServices(false)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, 18, len(count))
|
|
||||||
|
|
||||||
err = service.Delete()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
services := All()
|
|
||||||
assert.Equal(t, 17, len(services))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServiceCloseRoutine(t *testing.T) {
|
|
||||||
s := new(Service)
|
|
||||||
s.Name = "example"
|
|
||||||
s.Domain = "https://google.com"
|
|
||||||
s.Type = "http"
|
|
||||||
s.Method = "GET"
|
|
||||||
s.ExpectedStatus = 200
|
|
||||||
s.Interval = 1
|
|
||||||
s.Start()
|
|
||||||
assert.True(t, s.IsRunning())
|
|
||||||
t.Log(s.Checkpoint)
|
|
||||||
t.Log(s.SleepDuration)
|
|
||||||
go ServiceCheckQueue(s, false)
|
|
||||||
t.Log(s.Checkpoint)
|
|
||||||
t.Log(s.SleepDuration)
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
t.Log(s.Checkpoint)
|
|
||||||
t.Log(s.SleepDuration)
|
|
||||||
assert.True(t, s.IsRunning())
|
|
||||||
s.Close()
|
|
||||||
assert.False(t, s.IsRunning())
|
|
||||||
s.Close()
|
|
||||||
assert.False(t, s.IsRunning())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestServiceCheckQueue(t *testing.T) {
|
|
||||||
s := new(Service)
|
|
||||||
s.Name = "example"
|
|
||||||
s.Domain = "https://google.com"
|
|
||||||
s.Type = "http"
|
|
||||||
s.Method = "GET"
|
|
||||||
s.ExpectedStatus = 200
|
|
||||||
s.Interval = 1
|
|
||||||
s.Start()
|
|
||||||
assert.True(t, s.IsRunning())
|
|
||||||
go ServiceCheckQueue(s, false)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
t.Log(s.Checkpoint)
|
|
||||||
time.Sleep(6 * time.Second)
|
|
||||||
}()
|
|
||||||
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
assert.True(t, s.IsRunning())
|
|
||||||
s.Close()
|
|
||||||
assert.False(t, s.IsRunning())
|
|
||||||
s.Close()
|
|
||||||
assert.False(t, s.IsRunning())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDNScheckService(t *testing.T) {
|
|
||||||
s := new(Service)
|
|
||||||
s.Name = "example"
|
|
||||||
s.Domain = "http://localhost:9000"
|
|
||||||
s.Type = "http"
|
|
||||||
s.Method = "GET"
|
|
||||||
s.ExpectedStatus = 200
|
|
||||||
s.Interval = 1
|
|
||||||
amount, err := dnsCheck(s)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.NotZero(t, amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFindLink(t *testing.T) {
|
|
||||||
service, err := Find(1)
|
|
||||||
require.Nil(t, err)
|
|
||||||
assert.Equal(t, "google", service.Permalink.String)
|
|
||||||
}
|
|
|
@ -51,10 +51,10 @@ func durationStr(d time.Duration) string {
|
||||||
return "2006-01-02T00:00:00Z"
|
return "2006-01-02T00:00:00Z"
|
||||||
|
|
||||||
case m >= Day.Seconds():
|
case m >= Day.Seconds():
|
||||||
return "2006-01-02T15:00:00Z"
|
return "2006-01-02T00:00:00Z"
|
||||||
|
|
||||||
case m >= Hour.Seconds():
|
case m >= Hour.Seconds():
|
||||||
return "2006-01-02T15:04:00Z"
|
return "2006-01-02T15:00:00Z"
|
||||||
|
|
||||||
case m >= Minute.Seconds():
|
case m >= Minute.Seconds():
|
||||||
return "2006-01-02T15:04:00Z"
|
return "2006-01-02T15:04:00Z"
|
||||||
|
|
|
@ -33,14 +33,6 @@ func TestFixedTime(t *testing.T) {
|
||||||
timeVal,
|
timeVal,
|
||||||
Day,
|
Day,
|
||||||
"2020-05-22T00:00:00Z",
|
"2020-05-22T00:00:00Z",
|
||||||
}, {
|
|
||||||
timeVal.Add(2 * Month),
|
|
||||||
Month,
|
|
||||||
"2020-07-01T00:00:00Z",
|
|
||||||
}, {
|
|
||||||
timeVal.Add(2 * Year),
|
|
||||||
Year,
|
|
||||||
"2022-01-01T00:00:00Z",
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
for _, e := range examples {
|
for _, e := range examples {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"github.com/hunterlong/statping/types/null"
|
"github.com/hunterlong/statping/types/null"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Samples() {
|
func Samples() error {
|
||||||
u2 := &User{
|
u2 := &User{
|
||||||
Username: "testadmin",
|
Username: "testadmin",
|
||||||
Password: "password123",
|
Password: "password123",
|
||||||
|
@ -12,7 +12,9 @@ func Samples() {
|
||||||
Admin: null.NewNullBool(true),
|
Admin: null.NewNullBool(true),
|
||||||
}
|
}
|
||||||
|
|
||||||
u2.Create()
|
if err := u2.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
u3 := &User{
|
u3 := &User{
|
||||||
Username: "testadmin2",
|
Username: "testadmin2",
|
||||||
|
@ -21,5 +23,9 @@ func Samples() {
|
||||||
Admin: null.NewNullBool(true),
|
Admin: null.NewNullBool(true),
|
||||||
}
|
}
|
||||||
|
|
||||||
u3.Create()
|
if err := u3.Create(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ type User struct {
|
||||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||||
Username string `gorm:"type:varchar(100);unique;column:username;" json:"username,omitempty"`
|
Username string `gorm:"type:varchar(100);unique;column:username;" json:"username,omitempty"`
|
||||||
Password string `gorm:"column:password" json:"password,omitempty"`
|
Password string `gorm:"column:password" json:"password,omitempty"`
|
||||||
Email string `gorm:"type:varchar(100);unique;column:email" json:"email,omitempty"`
|
Email string `gorm:"type:varchar(100);column:email" json:"email,omitempty"`
|
||||||
ApiKey string `gorm:"column:api_key" json:"api_key,omitempty"`
|
ApiKey string `gorm:"column:api_key" json:"api_key,omitempty"`
|
||||||
ApiSecret string `gorm:"column:api_secret" json:"api_secret,omitempty"`
|
ApiSecret string `gorm:"column:api_secret" json:"api_secret,omitempty"`
|
||||||
Admin null.NullBool `gorm:"column:administrator" json:"admin,omitempty"`
|
Admin null.NullBool `gorm:"column:administrator" json:"admin,omitempty"`
|
||||||
|
|
|
@ -1,117 +0,0 @@
|
||||||
// Statping
|
|
||||||
// Copyright (C) 2018. Hunter Long and the project contributors
|
|
||||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
|
|
||||||
//
|
|
||||||
// https://github.com/hunterlong/statping
|
|
||||||
//
|
|
||||||
// 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 users
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hunterlong/statping/database"
|
|
||||||
"github.com/hunterlong/statping/types/null"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCreateUser(t *testing.T) {
|
|
||||||
user := &User{
|
|
||||||
Username: "hunter",
|
|
||||||
Password: "password123",
|
|
||||||
Email: "test@email.com",
|
|
||||||
Admin: null.NewNullBool(true),
|
|
||||||
}
|
|
||||||
err := user.Create()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.NotZero(t, user.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectAllUsers(t *testing.T) {
|
|
||||||
users := All()
|
|
||||||
assert.Equal(t, 3, len(users))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectUser(t *testing.T) {
|
|
||||||
user, err := Find(1)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "info@betatude.com", user.Email)
|
|
||||||
assert.True(t, user.Admin.Bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectUsername(t *testing.T) {
|
|
||||||
user, err := FindByUsername("hunter")
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "test@email.com", user.Email)
|
|
||||||
assert.Equal(t, int64(3), user.Id)
|
|
||||||
assert.True(t, user.Admin.Bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateUser(t *testing.T) {
|
|
||||||
user, err := Find(1)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
user.Username = "updated"
|
|
||||||
err = user.Update()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
updatedUser, err := Find(1)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "updated", updatedUser.Username)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateUser2(t *testing.T) {
|
|
||||||
user := &User{
|
|
||||||
Username: "hunterlong",
|
|
||||||
Password: "password123",
|
|
||||||
Email: "User@email.com",
|
|
||||||
Admin: null.NewNullBool(true),
|
|
||||||
}
|
|
||||||
err := user.Create()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.NotZero(t, user.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSelectAllUsersAgain(t *testing.T) {
|
|
||||||
users := All()
|
|
||||||
assert.Equal(t, 4, len(users))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAuthUser(t *testing.T) {
|
|
||||||
user, auth := AuthUser("hunterlong", "password123")
|
|
||||||
assert.True(t, auth)
|
|
||||||
assert.NotNil(t, user)
|
|
||||||
assert.Equal(t, "User@email.com", user.Email)
|
|
||||||
assert.Equal(t, int64(4), user.Id)
|
|
||||||
assert.True(t, user.Admin.Bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFailedAuthUser(t *testing.T) {
|
|
||||||
user, auth := AuthUser("hunterlong", "wrongpassword")
|
|
||||||
assert.False(t, auth)
|
|
||||||
assert.Nil(t, user)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckPassword(t *testing.T) {
|
|
||||||
user, err := Find(2)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
pass := CheckHash("password123", user.Password)
|
|
||||||
assert.True(t, pass)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteUser(t *testing.T) {
|
|
||||||
user, err := Find(2)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
err = user.Delete()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDbConfig_Close(t *testing.T) {
|
|
||||||
err := database.Close()
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
Loading…
Reference in New Issue