From f491cbd0199e4edaec5e494e21e34de236d49dd4 Mon Sep 17 00:00:00 2001 From: Hunter Long Date: Sun, 26 Jan 2020 13:01:43 -0800 Subject: [PATCH] updates --- .gitignore | 1 + Makefile | 6 +- core/checkin.go | 32 +- core/core.go | 8 +- core/database.go | 58 +- core/export.go | 22 - core/failures.go | 38 +- core/groups.go | 6 +- core/hits.go | 33 +- core/incidents.go | 10 +- core/messages.go | 18 +- core/notifier/notifiers.go | 17 +- core/sample.go | 12 +- core/services.go | 70 +-- core/users.go | 26 +- frontend/config/webpack.config.dev.js | 2 +- frontend/config/webpack.config.prod.js | 8 +- frontend/package.json | 6 +- frontend/src/App.vue | 36 +- {source => frontend/src/assets}/css/base.css | 2 +- .../src/assets}/css/bootstrap.min.css | 0 .../src/assets}/css/flatpickr.min.css | 0 {source => frontend/src/assets}/font/all.css | 0 .../src/assets}/font/all.min.css | 0 .../assets}/font/webfonts/fa-brands-400.eot | Bin .../assets}/font/webfonts/fa-brands-400.svg | 0 .../assets}/font/webfonts/fa-brands-400.ttf | Bin .../assets}/font/webfonts/fa-brands-400.woff | Bin .../assets}/font/webfonts/fa-brands-400.woff2 | Bin .../assets}/font/webfonts/fa-regular-400.eot | Bin .../assets}/font/webfonts/fa-regular-400.svg | 0 .../assets}/font/webfonts/fa-regular-400.ttf | Bin .../assets}/font/webfonts/fa-regular-400.woff | Bin .../font/webfonts/fa-regular-400.woff2 | Bin .../assets}/font/webfonts/fa-solid-900.eot | Bin .../assets}/font/webfonts/fa-solid-900.svg | 0 .../assets}/font/webfonts/fa-solid-900.ttf | Bin .../assets}/font/webfonts/fa-solid-900.woff | Bin .../assets}/font/webfonts/fa-solid-900.woff2 | Bin .../src/assets}/js/bootstrap.min.js | 0 .../src/assets}/js/flatpickr.js | 0 .../src/assets}/js/rangePlugin.js | 0 .../src/assets}/scss/base.scss | 0 .../src/assets}/scss/mobile.scss | 0 .../src/assets}/scss/variables.scss | 0 frontend/src/components/API.js | 12 + .../components/Dashboard/DashboardIndex.vue | 9 +- .../src/components/Dashboard/ServiceInfo.vue | 48 +- .../components/Dashboard/ServiceSparkLine.vue | 67 +++ .../src/components/Service/ServiceChart.vue | 4 +- frontend/src/forms/Login.vue | 57 -- frontend/src/forms/Service.vue | 33 +- frontend/src/main.js | 96 +--- frontend/src/mixin.js | 14 + frontend/src/pages/Dashboard.vue | 9 +- frontend/src/pages/Login.vue | 59 +- frontend/src/routes.js | 91 +++ frontend/src/store.js | 4 +- frontend/vue.config.js | 1 + frontend/yarn.lock | 85 +-- handlers/handlers.go | 70 +-- handlers/index.go | 2 +- handlers/middleware.go | 27 + handlers/routes.go | 57 +- handlers/services.go | 9 +- handlers/settings.go | 2 +- source/js/apexcharts.min.js | 14 - source/js/chart_index.js | 137 ----- source/js/charts.js | 141 ----- source/js/inputTags.min.js | 1 - source/js/jquery-3.3.1.min.js | 2 - source/js/main.js | 492 ---------------- source/js/setup.js | 57 -- source/js/sortable.min.js | 2 - source/source.go | 18 +- source/tmpl/bulk_import.csv | 11 - source/tmpl/dashboard.gohtml | 208 ------- source/tmpl/error_404.gohtml | 10 - source/tmpl/footer.gohtml | 9 - source/tmpl/form_checkin.gohtml | 27 - source/tmpl/form_group.gohtml | 31 - source/tmpl/form_incident.gohtml | 84 --- source/tmpl/form_integration.gohtml | 32 -- source/tmpl/form_message.gohtml | 84 --- source/tmpl/form_notifier.gohtml | 73 --- source/tmpl/form_service.gohtml | 170 ------ source/tmpl/form_user.gohtml | 45 -- source/tmpl/group.gohtml | 17 - source/tmpl/head.gohtml | 21 - source/tmpl/help.gohtml | 28 - source/tmpl/index.gohtml | 108 ---- source/tmpl/integrator.gohtml | 90 --- source/tmpl/login.gohtml | 34 -- source/tmpl/logs.gohtml | 20 - source/tmpl/message.gohtml | 27 - source/tmpl/messages.gohtml | 59 -- source/tmpl/nav.gohtml | 40 -- source/tmpl/scripts.gohtml | 14 - source/tmpl/service.gohtml | 395 ------------- source/tmpl/service_create.gohtml | 9 - source/tmpl/services.gohtml | 148 ----- source/tmpl/settings.gohtml | 325 ----------- source/tmpl/setup.gohtml | 96 ---- source/tmpl/tray.gohtml | 100 ---- source/tmpl/user.gohtml | 10 - source/tmpl/users.gohtml | 34 -- source/wiki.go | 2 +- types/gorm.go | 534 ++++++++++++++++++ utils/utils.go | 8 + 109 files changed, 1149 insertions(+), 3785 deletions(-) rename {source => frontend/src/assets}/css/base.css (99%) rename {source => frontend/src/assets}/css/bootstrap.min.css (100%) rename {source => frontend/src/assets}/css/flatpickr.min.css (100%) rename {source => frontend/src/assets}/font/all.css (100%) rename {source => frontend/src/assets}/font/all.min.css (100%) rename {source => frontend/src/assets}/font/webfonts/fa-brands-400.eot (100%) rename {source => frontend/src/assets}/font/webfonts/fa-brands-400.svg (100%) rename {source => frontend/src/assets}/font/webfonts/fa-brands-400.ttf (100%) rename {source => frontend/src/assets}/font/webfonts/fa-brands-400.woff (100%) rename {source => frontend/src/assets}/font/webfonts/fa-brands-400.woff2 (100%) rename {source => frontend/src/assets}/font/webfonts/fa-regular-400.eot (100%) rename {source => frontend/src/assets}/font/webfonts/fa-regular-400.svg (100%) rename {source => frontend/src/assets}/font/webfonts/fa-regular-400.ttf (100%) rename {source => frontend/src/assets}/font/webfonts/fa-regular-400.woff (100%) rename {source => frontend/src/assets}/font/webfonts/fa-regular-400.woff2 (100%) rename {source => frontend/src/assets}/font/webfonts/fa-solid-900.eot (100%) rename {source => frontend/src/assets}/font/webfonts/fa-solid-900.svg (100%) rename {source => frontend/src/assets}/font/webfonts/fa-solid-900.ttf (100%) rename {source => frontend/src/assets}/font/webfonts/fa-solid-900.woff (100%) rename {source => frontend/src/assets}/font/webfonts/fa-solid-900.woff2 (100%) rename {source => frontend/src/assets}/js/bootstrap.min.js (100%) rename {source => frontend/src/assets}/js/flatpickr.js (100%) rename {source => frontend/src/assets}/js/rangePlugin.js (100%) rename {source => frontend/src/assets}/scss/base.scss (100%) rename {source => frontend/src/assets}/scss/mobile.scss (100%) rename {source => frontend/src/assets}/scss/variables.scss (100%) create mode 100644 frontend/src/components/Dashboard/ServiceSparkLine.vue delete mode 100644 frontend/src/forms/Login.vue create mode 100644 frontend/src/mixin.js delete mode 100644 source/js/apexcharts.min.js delete mode 100644 source/js/chart_index.js delete mode 100644 source/js/charts.js delete mode 100755 source/js/inputTags.min.js delete mode 100644 source/js/jquery-3.3.1.min.js delete mode 100644 source/js/main.js delete mode 100644 source/js/setup.js delete mode 100644 source/js/sortable.min.js delete mode 100644 source/tmpl/bulk_import.csv delete mode 100644 source/tmpl/dashboard.gohtml delete mode 100644 source/tmpl/error_404.gohtml delete mode 100644 source/tmpl/footer.gohtml delete mode 100644 source/tmpl/form_checkin.gohtml delete mode 100644 source/tmpl/form_group.gohtml delete mode 100644 source/tmpl/form_incident.gohtml delete mode 100644 source/tmpl/form_integration.gohtml delete mode 100644 source/tmpl/form_message.gohtml delete mode 100644 source/tmpl/form_notifier.gohtml delete mode 100644 source/tmpl/form_service.gohtml delete mode 100644 source/tmpl/form_user.gohtml delete mode 100644 source/tmpl/group.gohtml delete mode 100644 source/tmpl/head.gohtml delete mode 100644 source/tmpl/help.gohtml delete mode 100644 source/tmpl/index.gohtml delete mode 100644 source/tmpl/integrator.gohtml delete mode 100644 source/tmpl/login.gohtml delete mode 100644 source/tmpl/logs.gohtml delete mode 100644 source/tmpl/message.gohtml delete mode 100644 source/tmpl/messages.gohtml delete mode 100644 source/tmpl/nav.gohtml delete mode 100644 source/tmpl/scripts.gohtml delete mode 100644 source/tmpl/service.gohtml delete mode 100644 source/tmpl/service_create.gohtml delete mode 100644 source/tmpl/services.gohtml delete mode 100644 source/tmpl/settings.gohtml delete mode 100644 source/tmpl/setup.gohtml delete mode 100644 source/tmpl/tray.gohtml delete mode 100644 source/tmpl/user.gohtml delete mode 100644 source/tmpl/users.gohtml create mode 100644 types/gorm.go diff --git a/.gitignore b/.gitignore index 8b301ba3..3d89ec53 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ public .env logs tmp +source/dist /dev/test/node_modules dev/test/cypress/videos dev/test/cypress/screenshots diff --git a/Makefile b/Makefile index 638f7ab6..e1e1ecc0 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,8 @@ frontend: frontend-build: cd frontend && rm -rf dist && yarn build + rm -rf source/dist && cp -r frontend/dist source/ + cp -r source/tmpl/*.* source/dist/ # build and push the images to docker hub docker: docker-build-all docker-publish-all @@ -93,10 +95,8 @@ watch: -i="Makefile,statping,statup.db,statup.db-journal,handlers/graphql/generated.go" # compile assets using SASS and Rice. compiles scss -> css, and run rice embed-go -compile: generate - sass source/scss/base.scss source/css/base.css +compile: frontend-build generate cd source && rice embed-go - rm -rf .sass-cache # benchmark testing benchmark: diff --git a/core/checkin.go b/core/checkin.go index ac9e65ad..364c1277 100644 --- a/core/checkin.go +++ b/core/checkin.go @@ -99,11 +99,11 @@ func (c *Checkin) CreateFailure() (int64, error) { if len(c.Failures) > limitedFailures { c.Failures = c.Failures[1:] } - return fail.Id, row.Error + return fail.Id, row.Error() } // LimitedHits will return the last amount of successful hits from a checkin -func (c *Checkin) LimitedHits(amount int64) []*types.CheckinHit { +func (c *Checkin) LimitedHits(amount int) []*types.CheckinHit { var hits []*types.CheckinHit checkinHitsDB().Where("checkin = ?", c.Id).Order("id desc").Limit(amount).Find(&hits) return hits @@ -168,7 +168,7 @@ func (c *Checkin) AllHits() []*types.CheckinHit { } // Hits returns all of the CheckinHits for a given Checkin -func (c *Checkin) LimitedFailures(amount int64) []types.FailureInterface { +func (c *Checkin) LimitedFailures(amount int) []types.FailureInterface { var failures []*Failure var failInterfaces []types.FailureInterface col := failuresDB().Where("checkin = ?", c.Id).Where("method = 'checkin'").Limit(amount).Order("id desc") @@ -195,7 +195,7 @@ func (c *Checkin) Delete() error { slice := service.Checkins service.Checkins = append(slice[:i], slice[i+1:]...) row := checkinDB().Delete(&c) - return row.Error + return row.Error() } // index returns a checkin index int for updating the *checkin.Service slice @@ -212,25 +212,25 @@ func (c *Checkin) index() int { func (c *Checkin) Create() (int64, error) { c.ApiKey = utils.RandomString(7) row := checkinDB().Create(&c) - if row.Error != nil { - log.Warnln(row.Error) - return 0, row.Error + if row.Error() != nil { + log.Warnln(row.Error()) + return 0, row.Error() } service := SelectService(c.ServiceId) service.Checkins = append(service.Checkins, c) c.Start() go c.Routine() - return c.Id, row.Error + return c.Id, row.Error() } // Update will update a Checkin func (c *Checkin) Update() (int64, error) { row := checkinDB().Update(&c) - if row.Error != nil { - log.Warnln(row.Error) - return 0, row.Error + if row.Error() != nil { + log.Warnln(row.Error()) + return 0, row.Error() } - return c.Id, row.Error + return c.Id, row.Error() } // Create will create a new successful checkinHit @@ -239,11 +239,11 @@ func (c *CheckinHit) Create() (int64, error) { c.CreatedAt = utils.Now() } row := checkinHitsDB().Create(&c) - if row.Error != nil { - log.Warnln(row.Error) - return 0, row.Error + if row.Error() != nil { + log.Warnln(row.Error()) + return 0, row.Error() } - return c.Id, row.Error + return c.Id, row.Error() } // Ago returns the duration of time between now and the last successful checkinHit diff --git a/core/core.go b/core/core.go index f34bf820..79d2014f 100644 --- a/core/core.go +++ b/core/core.go @@ -89,7 +89,7 @@ func InsertNotifierDB() error { // UpdateCore will update the CoreApp variable inside of the 'core' table in database func UpdateCore(c *Core) (*Core, error) { db := coreDB().Update(&c) - return c, db.Error + return c, db.Error() } // CurrentTime will return the current local time @@ -159,12 +159,12 @@ func SelectCore() (*Core, error) { return nil, errors.New("core database has not been setup yet.") } db := coreDB().First(&CoreApp) - if db.Error != nil { - return nil, db.Error + if db.Error() != nil { + return nil, db.Error() } CoreApp.Version = VERSION CoreApp.UseCdn = types.NewNullBool(os.Getenv("USE_CDN") == "true") - return CoreApp, db.Error + return CoreApp, db.Error() } // GetLocalIP returns the non loopback local IP of the host diff --git a/core/database.go b/core/database.go index 2a78bde2..c23e487b 100644 --- a/core/database.go +++ b/core/database.go @@ -32,7 +32,7 @@ import ( var ( // DbSession stores the Statping database session - DbSession *gorm.DB + DbSession types.Database DbModels []interface{} ) @@ -48,62 +48,62 @@ func init() { type DbConfig types.DbConfig // failuresDB returns the 'failures' database column -func failuresDB() *gorm.DB { +func failuresDB() types.Database { return DbSession.Model(&types.Failure{}) } // hitsDB returns the 'hits' database column -func hitsDB() *gorm.DB { +func hitsDB() types.Database { return DbSession.Model(&types.Hit{}) } // servicesDB returns the 'services' database column -func servicesDB() *gorm.DB { +func servicesDB() types.Database { return DbSession.Model(&types.Service{}) } // coreDB returns the single column 'core' -func coreDB() *gorm.DB { +func coreDB() types.Database { return DbSession.Table("core").Model(&CoreApp) } // usersDB returns the 'users' database column -func usersDB() *gorm.DB { +func usersDB() types.Database { return DbSession.Model(&types.User{}) } // checkinDB returns the Checkin records for a service -func checkinDB() *gorm.DB { +func checkinDB() types.Database { return DbSession.Model(&types.Checkin{}) } // checkinHitsDB returns the Checkin Hits records for a service -func checkinHitsDB() *gorm.DB { +func checkinHitsDB() types.Database { return DbSession.Model(&types.CheckinHit{}) } // messagesDb returns the Checkin records for a service -func messagesDb() *gorm.DB { +func messagesDb() types.Database { return DbSession.Model(&types.Message{}) } // messagesDb returns the Checkin records for a service -func groupsDb() *gorm.DB { +func groupsDb() types.Database { return DbSession.Model(&types.Group{}) } // incidentsDB returns the 'incidents' database column -func incidentsDB() *gorm.DB { +func incidentsDB() types.Database { return DbSession.Model(&types.Incident{}) } // incidentsUpdatesDB returns the 'incidents updates' database column -func incidentsUpdatesDB() *gorm.DB { +func incidentsUpdatesDB() types.Database { return DbSession.Model(&types.IncidentUpdate{}) } // HitsBetween returns the gorm database query for a collection of service hits between a time range -func (s *Service) HitsBetween(t1, t2 time.Time, group string, column string) *gorm.DB { +func (s *Service) HitsBetween(t1, t2 time.Time, group string, column string) types.Database { selector := Dbtimestamp(group, column) if CoreApp.Config.DbConn == "postgres" { return hitsDB().Select(selector).Where("service = ? AND created_at BETWEEN ? AND ?", s.Id, t1.UTC().Format(types.TIME), t2.UTC().Format(types.TIME)) @@ -187,7 +187,7 @@ func (c *Core) InsertCore(db *types.DbConfig) (*Core, error) { Config: db, }} query := coreDB().Create(&CoreApp) - return CoreApp, query.Error + return CoreApp, query.Error() } func findDbFile() string { @@ -242,7 +242,7 @@ func (c *Core) Connect(retry bool, location string) error { conn = fmt.Sprintf("sqlserver://%v:%v@%v?database=%v", CoreApp.Config.DbUser, CoreApp.Config.DbPass, host, CoreApp.Config.DbData) } log.WithFields(utils.ToFields(c, conn)).Debugln("attempting to connect to database") - dbSession, err := gorm.Open(dbType, conn) + dbSession, err := types.Openw(dbType, conn) if err != nil { log.Debugln(fmt.Sprintf("Database connection error %v", err)) if retry { @@ -261,7 +261,7 @@ func (c *Core) Connect(retry bool, location string) error { if dbSession.DB().Ping() == nil { DbSession = dbSession if utils.VerboseMode >= 4 { - DbSession.LogMode(true).Debug().SetLogger(log) + DbSession.LogMode(true).Debug().SetLogger(gorm.Logger{log}) } log.Infoln(fmt.Sprintf("Database %v connection was successful.", dbType)) } @@ -289,8 +289,8 @@ func DatabaseMaintence() { func DeleteAllSince(table string, date time.Time) { sql := fmt.Sprintf("DELETE FROM %v WHERE created_at < '%v';", table, date.Format("2006-01-02")) db := DbSession.Exec(sql) - if db.Error != nil { - log.Warnln(db.Error) + if db.Error() != nil { + log.Warnln(db.Error()) } } @@ -346,7 +346,7 @@ func (c *Core) CreateCore() *Core { MigrationId: time.Now().Unix(), } db := coreDB().Create(&newCore) - if db.Error == nil { + if db.Error() == nil { CoreApp = &Core{Core: newCore} } CoreApp, err := SelectCore() @@ -370,7 +370,7 @@ func (c *Core) DropDatabase() error { err = DbSession.DropTableIfExists("messages") err = DbSession.DropTableIfExists("incidents") err = DbSession.DropTableIfExists("incident_updates") - return err.Error + return err.Error() } // CreateDatabase will CREATE TABLES for each of the Statping elements @@ -378,12 +378,12 @@ func (c *Core) CreateDatabase() error { var err error log.Infoln("Creating Database Tables...") for _, table := range DbModels { - if err := DbSession.CreateTable(table); err.Error != nil { - return err.Error + if err := DbSession.CreateTable(table); err.Error() != nil { + return err.Error() } } - if err := DbSession.Table("core").CreateTable(&types.Core{}); err.Error != nil { - return err.Error + if err := DbSession.Table("core").CreateTable(&types.Core{}); err.Error() != nil { + return err.Error() } log.Infoln("Statping Database Created") return err @@ -401,17 +401,17 @@ func (c *Core) MigrateDatabase() error { } }() if tx.Error != nil { - log.Errorln(tx.Error) - return tx.Error + log.Errorln(tx.Error()) + return tx.Error() } for _, table := range DbModels { tx = tx.AutoMigrate(table) } - if err := tx.Table("core").AutoMigrate(&types.Core{}); err.Error != nil { + if err := tx.Table("core").AutoMigrate(&types.Core{}); err.Error() != nil { tx.Rollback() log.Errorln(fmt.Sprintf("Statping Database could not be migrated: %v", tx.Error)) - return tx.Error + return tx.Error() } log.Infoln("Statping Database Migrated") - return tx.Commit().Error + return tx.Commit().Error() } diff --git a/core/export.go b/core/export.go index 2f880727..3339ce81 100644 --- a/core/export.go +++ b/core/export.go @@ -16,33 +16,11 @@ package core import ( - "bytes" "encoding/json" - "github.com/hunterlong/statping/source" "github.com/hunterlong/statping/types" - "html/template" ) // ExportChartsJs renders the charts for the index page -func ExportChartsJs() string { - render, err := source.JsBox.String("charts.js") - if err != nil { - log.Errorln(err) - } - t := template.New("charts") - t.Funcs(template.FuncMap{ - "safe": func(html string) template.HTML { - return template.HTML(html) - }, - }) - t.Parse(render) - var tpl bytes.Buffer - if err := t.Execute(&tpl, CoreApp.Services); err != nil { - log.Errorln(err) - } - result := tpl.String() - return result -} type ExportData struct { Core *types.Core `json:"core"` diff --git a/core/failures.go b/core/failures.go index d589bf42..3cc23d37 100644 --- a/core/failures.go +++ b/core/failures.go @@ -19,6 +19,7 @@ import ( "fmt" "github.com/ararog/timeago" "github.com/hunterlong/statping/types" + "net/http" "sort" "strings" "time" @@ -37,48 +38,51 @@ const ( func (s *Service) CreateFailure(f *types.Failure) (int64, error) { f.Service = s.Id row := failuresDB().Create(f) - if row.Error != nil { - log.Errorln(row.Error) - return 0, row.Error + if row.Error() != nil { + log.Errorln(row.Error()) + return 0, row.Error() } sort.Sort(types.FailSort(s.Failures)) //s.Failures = append(s.Failures, f) if len(s.Failures) > limitedFailures { s.Failures = s.Failures[1:] } - return f.Id, row.Error + return f.Id, row.Error() } // AllFailures will return all failures attached to a service -func (s *Service) AllFailures() []*types.Failure { - var fails []*types.Failure - col := failuresDB().Where("service = ?", s.Id).Not("method = 'checkin'").Order("id desc") - err := col.Find(&fails) - if err.Error != nil { +func (s *Service) AllFailures() []types.Failure { + var fails []types.Failure + err := DbSession.Failures(s.Id).Find(&fails) + if err.Error() != nil { log.Errorln(fmt.Sprintf("Issue getting failures for service %v, %v", s.Name, err)) return nil } return fails } +func (s *Service) FailuresDb(r *http.Request) types.Database { + return failuresDB().Where("service = ?", s.Id).QuerySearch(r).Order("id desc") +} + // DeleteFailures will delete all failures for a service func (s *Service) DeleteFailures() { err := DbSession.Exec(`DELETE FROM failures WHERE service = ?`, s.Id) - if err.Error != nil { + if err.Error() != nil { log.Errorln(fmt.Sprintf("failed to delete all failures: %v", err)) } s.Failures = nil } // LimitedFailures will return the last amount of failures from a service -func (s *Service) LimitedFailures(amount int64) []*Failure { +func (s *Service) LimitedFailures(amount int) []*Failure { var failArr []*Failure failuresDB().Where("service = ?", s.Id).Not("method = 'checkin'").Order("id desc").Limit(amount).Find(&failArr) return failArr } // LimitedFailures will return the last amount of failures from a service -func (s *Service) LimitedCheckinFailures(amount int64) []*Failure { +func (s *Service) LimitedCheckinFailures(amount int) []*Failure { var failArr []*Failure failuresDB().Where("service = ?", s.Id).Where("method = 'checkin'").Order("id desc").Limit(amount).Find(&failArr) return failArr @@ -98,7 +102,7 @@ func (f *Failure) Select() *types.Failure { // Delete will remove a Failure record from the database func (f *Failure) Delete() error { db := failuresDB().Delete(f) - return db.Error + return db.Error() } // Count24HFailures returns the amount of failures for a service within the last 24 hours @@ -116,7 +120,7 @@ func (c *Core) Count24HFailures() uint64 { func CountFailures() uint64 { var count uint64 err := failuresDB().Count(&count) - if err.Error != nil { + if err.Error() != nil { log.Warnln(err.Error) return 0 } @@ -130,7 +134,7 @@ func (s *Service) TotalFailuresOnDate(ago time.Time) (uint64, error) { dateend := ago.UTC().Format("2006-01-02") + " 23:59:59" rows := failuresDB().Where("service = ? AND created_at BETWEEN ? AND ?", s.Id, date, dateend).Not("method = 'checkin'") err := rows.Count(&count) - return count, err.Error + return count, err.Error() } // TotalFailures24 returns the amount of failures for a service within the last 24 hours @@ -144,7 +148,7 @@ func (s *Service) TotalFailures() (uint64, error) { var count uint64 rows := failuresDB().Where("service = ?", s.Id) err := rows.Count(&count) - return count, err.Error + return count, err.Error() } // FailuresDaysAgo returns the amount of failures since days ago @@ -159,7 +163,7 @@ func (s *Service) TotalFailuresSince(ago time.Time) (uint64, error) { var count uint64 rows := failuresDB().Where("service = ? AND created_at > ?", s.Id, ago.UTC().Format("2006-01-02 15:04:05")).Not("method = 'checkin'") err := rows.Count(&count) - return count, err.Error + return count, err.Error() } // ParseError returns a human readable error for a Failure diff --git a/core/groups.go b/core/groups.go index ece555a1..3b4338a2 100644 --- a/core/groups.go +++ b/core/groups.go @@ -17,21 +17,21 @@ func (g *Group) Delete() error { s.Update(false) } err := groupsDb().Delete(g) - return err.Error + return err.Error() } // Create will create a group and insert it into the database func (g *Group) Create() (int64, error) { g.CreatedAt = time.Now().UTC() db := groupsDb().Create(g) - return g.Id, db.Error + return g.Id, db.Error() } // Update will update a group func (g *Group) Update() (int64, error) { g.UpdatedAt = time.Now().UTC() db := groupsDb().Update(g) - return g.Id, db.Error + return g.Id, db.Error() } // Services returns all services belonging to a group diff --git a/core/hits.go b/core/hits.go index 7939cb41..cbe8c379 100644 --- a/core/hits.go +++ b/core/hits.go @@ -17,6 +17,7 @@ package core import ( "github.com/hunterlong/statping/types" + "net/http" "time" ) @@ -27,11 +28,11 @@ type Hit struct { // CreateHit will create a new 'hit' record in the database for a successful/online service func (s *Service) CreateHit(h *types.Hit) (int64, error) { db := hitsDB().Create(&h) - if db.Error != nil { - log.Errorln(db.Error) - return 0, db.Error + if db.Error() != nil { + log.Errorln(db.Error()) + return 0, db.Error() } - return h.Id, db.Error + return h.Id, db.Error() } // CountHits returns a int64 for all hits for a service @@ -39,7 +40,19 @@ func (s *Service) CountHits() (int64, error) { var hits int64 col := hitsDB().Where("service = ?", s.Id) err := col.Count(&hits) - return hits, err.Error + return hits, err.Error() +} + +// Hits returns all successful hits for a service +func (s *Service) HitsQuery(r *http.Request) ([]*types.Hit, error) { + var hits []*types.Hit + col := hitsDB().Where("service = ?", s.Id).QuerySearch(r).Order("id desc") + err := col.Find(&hits) + return hits, err.Error() +} + +func (s *Service) HitsDb(r *http.Request) types.Database { + return hitsDB().Where("service = ?", s.Id).QuerySearch(r).Order("id desc") } // Hits returns all successful hits for a service @@ -47,15 +60,15 @@ func (s *Service) Hits() ([]*types.Hit, error) { var hits []*types.Hit col := hitsDB().Where("service = ?", s.Id).Order("id desc") err := col.Find(&hits) - return hits, err.Error + return hits, err.Error() } // LimitedHits returns the last 1024 successful/online 'hit' records for a service -func (s *Service) LimitedHits(amount int64) ([]*types.Hit, error) { +func (s *Service) LimitedHits(amount int) ([]*types.Hit, error) { var hits []*types.Hit col := hitsDB().Where("service = ?", s.Id).Order("id desc").Limit(amount) err := col.Find(&hits) - return reverseHits(hits), err.Error + return reverseHits(hits), err.Error() } // reverseHits will reverse the service's hit slice @@ -70,14 +83,14 @@ func reverseHits(input []*types.Hit) []*types.Hit { func (s *Service) TotalHits() (uint64, error) { var count uint64 col := hitsDB().Where("service = ?", s.Id).Count(&count) - return count, col.Error + return count, col.Error() } // TotalHitsSince returns the total amount of hits based on a specific time/date func (s *Service) TotalHitsSince(ago time.Time) (uint64, error) { var count uint64 rows := hitsDB().Where("service = ? AND created_at > ?", s.Id, ago.UTC().Format("2006-01-02 15:04:05")).Count(&count) - return count, rows.Error + return count, rows.Error() } // Sum returns the added value Latency for all of the services successful hits. diff --git a/core/incidents.go b/core/incidents.go index af1a5df8..7db8e2fe 100644 --- a/core/incidents.go +++ b/core/incidents.go @@ -42,32 +42,32 @@ func (i *Incident) AllUpdates() []*IncidentUpdate { // Delete will remove a incident func (i *Incident) Delete() error { err := incidentsDB().Delete(i) - return err.Error + return err.Error() } // Create will create a incident and insert it into the database func (i *Incident) Create() (int64, error) { i.CreatedAt = time.Now().UTC() db := incidentsDB().Create(i) - return i.Id, db.Error + return i.Id, db.Error() } // Update will update a incident func (i *Incident) Update() (int64, error) { i.UpdatedAt = time.Now().UTC() db := incidentsDB().Update(i) - return i.Id, db.Error + return i.Id, db.Error() } // Delete will remove a incident update func (i *IncidentUpdate) Delete() error { err := incidentsUpdatesDB().Delete(i) - return err.Error + return err.Error() } // Create will create a incident update and insert it into the database func (i *IncidentUpdate) Create() (int64, error) { i.CreatedAt = time.Now().UTC() db := incidentsUpdatesDB().Create(i) - return i.Id, db.Error + return i.Id, db.Error() } diff --git a/core/messages.go b/core/messages.go index a1f4d066..ae226d2f 100644 --- a/core/messages.go +++ b/core/messages.go @@ -41,14 +41,14 @@ func ReturnMessage(m *types.Message) *Message { func SelectMessages() ([]*Message, error) { var messages []*Message db := messagesDb().Find(&messages).Order("id desc") - return messages, db.Error + return messages, db.Error() } // SelectMessage returns a Message based on the ID passed func SelectMessage(id int64) (*Message, error) { var message Message db := messagesDb().Where("id = ?", id).Find(&message) - return &message, db.Error + return &message, db.Error() } func (m *Message) Service() *Service { @@ -62,9 +62,9 @@ func (m *Message) Service() *Service { func (m *Message) Create() (int64, error) { m.CreatedAt = time.Now().UTC() db := messagesDb().Create(m) - if db.Error != nil { - log.Errorln(fmt.Sprintf("Failed to create message %v #%v: %v", m.Title, m.Id, db.Error)) - return 0, db.Error + if db.Error() != nil { + log.Errorln(fmt.Sprintf("Failed to create message %v #%v: %v", m.Title, m.Id, db.Error())) + return 0, db.Error() } return m.Id, nil } @@ -72,15 +72,15 @@ func (m *Message) Create() (int64, error) { // Delete will delete a Message from database func (m *Message) Delete() error { db := messagesDb().Delete(m) - return db.Error + return db.Error() } // Update will update a Message in the database func (m *Message) Update() (*Message, error) { db := messagesDb().Update(m) - if db.Error != nil { - log.Errorln(fmt.Sprintf("Failed to update message %v #%v: %v", m.Title, m.Id, db.Error)) - return nil, db.Error + if db.Error() != nil { + log.Errorln(fmt.Sprintf("Failed to update message %v #%v: %v", m.Title, m.Id, db.Error())) + return nil, db.Error() } return m, nil } diff --git a/core/notifier/notifiers.go b/core/notifier/notifiers.go index 321b0357..e5b68ee7 100644 --- a/core/notifier/notifiers.go +++ b/core/notifier/notifiers.go @@ -21,7 +21,6 @@ import ( "fmt" "github.com/hunterlong/statping/types" "github.com/hunterlong/statping/utils" - "github.com/jinzhu/gorm" "reflect" "strings" "time" @@ -31,7 +30,7 @@ var ( // AllCommunications holds all the loaded notifiers AllCommunications []types.AllNotifiers // db holds the Statping database connection - db *gorm.DB + db types.Database timezone float32 log = utils.Log.WithField("type", "notifier") ) @@ -112,12 +111,12 @@ func (n *Notification) CanTest() bool { } // db will return the notifier database column/record -func modelDb(n *Notification) *gorm.DB { +func modelDb(n *Notification) types.Database { return db.Model(&Notification{}).Where("method = ?", n.Method).Find(n) } // SetDB is called by core to inject the database for a notifier to use -func SetDB(d *gorm.DB, zone float32) { +func SetDB(d types.Database, zone float32) { db = d timezone = zone } @@ -199,7 +198,7 @@ func isInDatabase(n Notifier) bool { func SelectNotification(n Notifier) (*Notification, error) { notifier := n.Select() err := db.Model(&Notification{}).Where("method = ?", notifier.Method).Scan(¬ifier) - return notifier, err.Error + return notifier, err.Error() } // Update will update the notification into the database @@ -213,7 +212,7 @@ func Update(n Notifier, notif *Notification) (*Notification, error) { } else { notif.close() } - return notif, err.Error + return notif, err.Error() } // insertDatabase will create a new record into the database for the notifier @@ -221,10 +220,10 @@ func insertDatabase(n Notifier) (int64, error) { noti := n.Select() noti.Limits = 3 query := db.Create(noti) - if query.Error != nil { - return 0, query.Error + if query.Error() != nil { + return 0, query.Error() } - return noti.Id, query.Error + return noti.Id, query.Error() } // SelectNotifier returns the Notification struct from the database diff --git a/core/sample.go b/core/sample.go index 6b0e4c9e..8d6bd8e0 100644 --- a/core/sample.go +++ b/core/sample.go @@ -231,7 +231,7 @@ func InsertSampleHits() error { }() } sg.Wait() - err := tx.Commit().Error + err := tx.Commit().Error() if err != nil { log.Errorln(err) } @@ -251,7 +251,7 @@ func insertSampleCore() error { UseCdn: types.NewNullBool(false), } query := coreDB().Create(core) - return query.Error + return query.Error() } // insertSampleUsers will create 2 admin users for a seed database @@ -457,13 +457,13 @@ func InsertLargeSampleData() error { } // insertFailureRecords will create failures for 15 services from seed -func insertFailureRecords(since time.Time, amount int64) { +func insertFailureRecords(since time.Time, amount int) { for i := int64(14); i <= 15; i++ { service := SelectService(i) log.Infoln(fmt.Sprintf("Adding %v Failure records to service %v", amount, service.Name)) createdAt := since - for fi := int64(1); fi <= amount; fi++ { + for fi := 1; fi <= amount; fi++ { createdAt = createdAt.Add(2 * time.Minute) failure := &types.Failure{ @@ -478,13 +478,13 @@ func insertFailureRecords(since time.Time, amount int64) { } // insertHitRecords will create successful Hit records for 15 services -func insertHitRecords(since time.Time, amount int64) { +func insertHitRecords(since time.Time, amount int) { for i := int64(1); i <= 15; i++ { service := SelectService(i) log.Infoln(fmt.Sprintf("Adding %v hit records to service %v", amount, service.Name)) createdAt := since p := utils.NewPerlin(2, 2, 5, time.Now().UnixNano()) - for hi := int64(1); hi <= amount; hi++ { + for hi := 1; hi <= amount; hi++ { latency := p.Noise1D(float64(hi / 10)) createdAt = createdAt.Add(1 * time.Minute) hit := &types.Hit{ diff --git a/core/services.go b/core/services.go index ebadefbe..103940f7 100644 --- a/core/services.go +++ b/core/services.go @@ -100,9 +100,9 @@ func (s *Service) AllCheckins() []*Checkin { func (c *Core) SelectAllServices(start bool) ([]*Service, error) { var services []*Service db := servicesDB().Find(&services).Order("order_id desc") - if db.Error != nil { - log.Errorln(fmt.Sprintf("service error: %v", db.Error)) - return nil, db.Error + if db.Error() != nil { + log.Errorln(fmt.Sprintf("service error: %v", db.Error())) + return nil, db.Error() } CoreApp.Services = nil for _, service := range services { @@ -123,7 +123,7 @@ func (c *Core) SelectAllServices(start bool) ([]*Service, error) { CoreApp.Services = append(CoreApp.Services, service) } reorderServices() - return services, db.Error + return services, db.Error() } // reorderServices will sort the services based on 'order_id' @@ -170,17 +170,6 @@ func (s *Service) OnlineSince(ago time.Time) float32 { return s.Online24Hours } -// DateScan struct is for creating the charts.js graph JSON array -type DateScan struct { - CreatedAt string `json:"x,omitempty"` - Value int64 `json:"y"` -} - -// DateScanObj struct is for creating the charts.js graph JSON array -type DateScanObj struct { - Array []DateScan `json:"data"` -} - // lastFailure returns the last Failure a service had func (s *Service) lastFailure() *Failure { limited := s.LimitedFailures(1) @@ -264,37 +253,20 @@ func (s *Service) Downtime() time.Duration { return since } +// DateScanObj struct is for creating the charts.js graph JSON array +type DateScanObj struct { + Array []*types.DateScan `json:"data"` +} + // GraphDataRaw will return all the hits between 2 times for a Service func GraphDataRaw(service types.ServiceInterface, start, end time.Time, group string, column string) *DateScanObj { - var data []DateScan - outgoing := new(DateScanObj) model := service.(*Service).HitsBetween(start, end, group, column) model = model.Order("timeframe asc", false).Group("timeframe") - rows, err := model.Rows() + outgoing, err := model.ToChart() if err != nil { - log.Errorln(fmt.Errorf("issue fetching service chart data: %v", err)) + log.Error(err) } - for rows.Next() { - var gd DateScan - var createdAt string - var value float64 - var createdTime time.Time - var err error - rows.Scan(&createdAt, &value) - if CoreApp.Config.DbConn == "postgres" { - createdTime, err = time.Parse(types.TIME_NANO, createdAt) - if err != nil { - log.Errorln(fmt.Errorf("issue parsing time from database: %v to %v", createdAt, types.TIME_NANO)) - } - } else { - createdTime, err = time.Parse(types.TIME, createdAt) - } - gd.CreatedAt = utils.Timezoner(createdTime, CoreApp.Timezone).Format(types.CHART_TIME) - gd.Value = int64(value * 1000) - data = append(data, gd) - } - outgoing.Array = data - return outgoing + return &DateScanObj{outgoing} } // ToString will convert the DateScanObj into a JSON string for the charts to render @@ -370,24 +342,24 @@ func updateService(s *Service) { func (s *Service) Delete() error { i := s.index() err := servicesDB().Delete(s) - if err.Error != nil { + if err.Error() != nil { log.Errorln(fmt.Sprintf("Failed to delete service %v. %v", s.Name, err.Error)) - return err.Error + return err.Error() } s.Close() slice := CoreApp.Services CoreApp.Services = append(slice[:i], slice[i+1:]...) reorderServices() notifier.OnDeletedService(s.Service) - return err.Error + return err.Error() } // Update will update a service in the database, the service's checking routine can be restarted by passing true func (s *Service) Update(restart bool) error { err := servicesDB().Update(&s) - if err.Error != nil { + if err.Error() != nil { log.Errorln(fmt.Sprintf("Failed to update service %v. %v", s.Name, err)) - return err.Error + return err.Error() } // clear the notification queue for a service if !s.AllowNotifications.Bool { @@ -405,16 +377,16 @@ func (s *Service) Update(restart bool) error { reorderServices() updateService(s) notifier.OnUpdatedService(s.Service) - return err.Error + return err.Error() } // Create will create a service and insert it into the database func (s *Service) Create(check bool) (int64, error) { s.CreatedAt = time.Now().UTC() db := servicesDB().Create(s) - if db.Error != nil { - log.Errorln(fmt.Sprintf("Failed to create service %v #%v: %v", s.Name, s.Id, db.Error)) - return 0, db.Error + if db.Error() != nil { + log.Errorln(fmt.Sprintf("Failed to create service %v #%v: %v", s.Name, s.Id, db.Error())) + return 0, db.Error() } s.Start() go s.CheckQueue(check) diff --git a/core/users.go b/core/users.go index e197454d..b2a6ea27 100644 --- a/core/users.go +++ b/core/users.go @@ -43,7 +43,7 @@ func CountUsers() int64 { func SelectUser(id int64) (*User, error) { var user User err := usersDB().Where("id = ?", id).First(&user) - return &user, err.Error + return &user, err.Error() } // SelectUsername returns the User based on the User's username @@ -51,19 +51,19 @@ func SelectUsername(username string) (*User, error) { var user User res := usersDB().Where("username = ?", username) err := res.First(&user) - return &user, err.Error + return &user, err.Error() } // Delete will remove the User record from the database func (u *User) Delete() error { - return usersDB().Delete(u).Error + return usersDB().Delete(u).Error() } // Update will update the User's record in database func (u *User) Update() error { u.ApiKey = utils.NewSHA1Hash(5) u.ApiSecret = utils.NewSHA1Hash(10) - return usersDB().Update(u).Error + return usersDB().Update(u).Error() } // Create will insert a new User into the database @@ -73,25 +73,25 @@ func (u *User) Create() (int64, error) { u.ApiKey = utils.NewSHA1Hash(5) u.ApiSecret = utils.NewSHA1Hash(10) db := usersDB().Create(u) - if db.Error != nil { - return 0, db.Error + if db.Error() != nil { + return 0, db.Error() } if u.Id == 0 { - log.Errorln(fmt.Sprintf("Failed to create User %v. %v", u.Username, db.Error)) - return 0, db.Error + log.Errorln(fmt.Sprintf("Failed to create User %v. %v", u.Username, db.Error())) + return 0, db.Error() } - return u.Id, db.Error + return u.Id, db.Error() } // SelectAllUsers returns all users func SelectAllUsers() ([]*User, error) { var users []*User db := usersDB().Find(&users) - if db.Error != nil { - log.Errorln(fmt.Sprintf("Failed to load all users. %v", db.Error)) - return nil, db.Error + if db.Error() != nil { + log.Errorln(fmt.Sprintf("Failed to load all users. %v", db.Error())) + return nil, db.Error() } - return users, db.Error + return users, db.Error() } // AuthUser will return the User and a boolean if authentication was correct. diff --git a/frontend/config/webpack.config.dev.js b/frontend/config/webpack.config.dev.js index 0f129982..7b19ba07 100644 --- a/frontend/config/webpack.config.dev.js +++ b/frontend/config/webpack.config.dev.js @@ -14,7 +14,7 @@ const webpackConfig = merge(commonConfig, { path: helpers.root('dist'), publicPath: '/', filename: 'js/[name].bundle.js', - chunkFilename: 'js/[id].chunk.js' + chunkFilename: 'js/[name].chunk.js' }, optimization: { runtimeChunk: 'single', diff --git a/frontend/config/webpack.config.prod.js b/frontend/config/webpack.config.prod.js index 80c45eec..f3ecab8a 100644 --- a/frontend/config/webpack.config.prod.js +++ b/frontend/config/webpack.config.prod.js @@ -16,8 +16,8 @@ const webpackConfig = merge(commonConfig, { output: { path: helpers.root('dist'), publicPath: '/', - filename: 'js/[hash].js', - chunkFilename: 'js/[id].[hash].chunk.js' + filename: 'js/[name].js', + chunkFilename: 'js/[name].chunk.js' }, optimization: { runtimeChunk: 'single', @@ -57,8 +57,8 @@ const webpackConfig = merge(commonConfig, { plugins: [ new webpack.EnvironmentPlugin(environment), new MiniCSSExtractPlugin({ - filename: 'css/[name].[hash].css', - chunkFilename: 'css/[id].[hash].css' + filename: 'css/[name].css', + chunkFilename: 'css/[name].[hash].css' }), new CompressionPlugin({ filename: '[path].gz[query]', diff --git a/frontend/package.json b/frontend/package.json index 6dee045f..aec50be9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -4,7 +4,7 @@ "private": true, "scripts": { "serve": "vue-cli-service serve", - "build": "cross-env NODE_ENV=production webpack", + "build": "rm -rf dist && cross-env NODE_ENV=production webpack", "dev": "cross-env NODE_ENV=development webpack-dev-server --progress", "lint": "vue-cli-service lint" }, @@ -56,9 +56,9 @@ "friendly-errors-webpack-plugin": "~1.7", "html-webpack-plugin": "~3.2", "mini-css-extract-plugin": "~0.5", - "node-sass": "~4.12", + "node-sass": "^4.13.1", "optimize-css-assets-webpack-plugin": "~5.0", - "sass-loader": "~7.1", + "sass-loader": "^8.0.2", "uglifyjs-webpack-plugin": "~1.2", "vue-loader": "~15.6", "vue-style-loader": "~4.1", diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 8ea4a84e..f53db808 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,5 +1,5 @@