mirror of https://github.com/statping/statping
vue
parent
f82abe9b49
commit
d2331fe14b
|
@ -65,7 +65,7 @@ func catchCLI(args []string) error {
|
|||
if err := runAssets(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := source.CompileSASS(dir); err != nil {
|
||||
if err := source.CompileSASS(); err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.New("end")
|
||||
|
|
|
@ -93,7 +93,7 @@ func (c *Checkin) CreateFailure() (int64, error) {
|
|||
Checkin: c.Id,
|
||||
PingTime: c.Expected().Seconds(),
|
||||
}}
|
||||
row := failuresDB().Create(&fail)
|
||||
row := Database(&Failure{}).Create(&fail)
|
||||
sort.Sort(types.FailSort(c.Failures))
|
||||
c.Failures = append(c.Failures, fail)
|
||||
if len(c.Failures) > limitedFailures {
|
||||
|
@ -105,14 +105,14 @@ func (c *Checkin) CreateFailure() (int64, error) {
|
|||
// LimitedHits will return the last amount of successful hits from a checkin
|
||||
func (c *Checkin) LimitedHits(amount int) []*types.CheckinHit {
|
||||
var hits []*types.CheckinHit
|
||||
checkinHitsDB().Where("checkin = ?", c.Id).Order("id desc").Limit(amount).Find(&hits)
|
||||
Database(&CheckinHit{}).Where("checkin = ?", c.Id).Order("id desc").Limit(amount).Find(&hits)
|
||||
return hits
|
||||
}
|
||||
|
||||
// AllCheckins returns all checkin in system
|
||||
func AllCheckins() []*Checkin {
|
||||
var checkins []*Checkin
|
||||
checkinDB().Find(&checkins)
|
||||
Database(&types.Checkin{}).Find(&checkins)
|
||||
return checkins
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ func (c *Checkin) Expected() time.Duration {
|
|||
// Last returns the last checkinHit for a Checkin
|
||||
func (c *Checkin) Last() *CheckinHit {
|
||||
var hit CheckinHit
|
||||
checkinHitsDB().Where("checkin = ?", c.Id).Last(&hit)
|
||||
Database(c).Where("checkin = ?", c.Id).Last(&hit)
|
||||
return &hit
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ func (c *Checkin) Link() string {
|
|||
// AllHits returns all of the CheckinHits for a given Checkin
|
||||
func (c *Checkin) AllHits() []*types.CheckinHit {
|
||||
var checkins []*types.CheckinHit
|
||||
checkinHitsDB().Where("checkin = ?", c.Id).Order("id DESC").Find(&checkins)
|
||||
Database(&types.CheckinHit{}).Where("checkin = ?", c.Id).Order("id DESC").Find(&checkins)
|
||||
return checkins
|
||||
}
|
||||
|
||||
|
@ -171,7 +171,7 @@ func (c *Checkin) AllHits() []*types.CheckinHit {
|
|||
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")
|
||||
col := Database(&types.Failure{}).Where("checkin = ?", c.Id).Where("method = 'checkin'").Limit(amount).Order("id desc")
|
||||
col.Find(&failures)
|
||||
for _, f := range failures {
|
||||
failInterfaces = append(failInterfaces, f)
|
||||
|
@ -182,7 +182,7 @@ func (c *Checkin) LimitedFailures(amount int) []types.FailureInterface {
|
|||
// Hits returns all of the CheckinHits for a given Checkin
|
||||
func (c *Checkin) AllFailures() []*types.Failure {
|
||||
var failures []*types.Failure
|
||||
col := failuresDB().Where("checkin = ?", c.Id).Where("method = 'checkin'").Order("id desc")
|
||||
col := Database(&types.Failure{}).Where("checkin = ?", c.Id).Where("method = 'checkin'").Order("id desc")
|
||||
col.Find(&failures)
|
||||
return failures
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ func (c *Checkin) Delete() error {
|
|||
service := c.Service()
|
||||
slice := service.Checkins
|
||||
service.Checkins = append(slice[:i], slice[i+1:]...)
|
||||
row := checkinDB().Delete(&c)
|
||||
row := Database(c).Delete(&c)
|
||||
return row.Error()
|
||||
}
|
||||
|
||||
|
@ -211,7 +211,7 @@ func (c *Checkin) index() int {
|
|||
// Create will create a new Checkin
|
||||
func (c *Checkin) Create() (int64, error) {
|
||||
c.ApiKey = utils.RandomString(7)
|
||||
row := checkinDB().Create(&c)
|
||||
row := Database(c).Create(&c)
|
||||
if row.Error() != nil {
|
||||
log.Warnln(row.Error())
|
||||
return 0, row.Error()
|
||||
|
@ -225,7 +225,7 @@ func (c *Checkin) Create() (int64, error) {
|
|||
|
||||
// Update will update a Checkin
|
||||
func (c *Checkin) Update() (int64, error) {
|
||||
row := checkinDB().Update(&c)
|
||||
row := Database(c).Update(&c)
|
||||
if row.Error() != nil {
|
||||
log.Warnln(row.Error())
|
||||
return 0, row.Error()
|
||||
|
@ -238,7 +238,7 @@ func (c *CheckinHit) Create() (int64, error) {
|
|||
if c.CreatedAt.IsZero() {
|
||||
c.CreatedAt = utils.Now()
|
||||
}
|
||||
row := checkinHitsDB().Create(&c)
|
||||
row := Database(c).Create(&c)
|
||||
if row.Error() != nil {
|
||||
log.Warnln(row.Error())
|
||||
return 0, row.Error()
|
||||
|
|
14
core/core.go
14
core/core.go
|
@ -83,7 +83,7 @@ func InsertNotifierDB() error {
|
|||
return errors.New("database connection has not been created")
|
||||
}
|
||||
}
|
||||
notifier.SetDB(DbSession, CoreApp.Timezone)
|
||||
notifier.SetDB(DbSession)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ func InsertIntegratorDB() error {
|
|||
|
||||
// UpdateCore will update the CoreApp variable inside of the 'core' table in database
|
||||
func UpdateCore(c *Core) (*Core, error) {
|
||||
db := coreDB().Update(&c)
|
||||
db := Database(&Core{}).Update(&c)
|
||||
return c, db.Error()
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ func (c Core) CurrentTime() string {
|
|||
// Messages will return the current local time
|
||||
func (c Core) Messages() []*Message {
|
||||
var message []*Message
|
||||
messagesDb().Where("service = ?", 0).Limit(10).Find(&message)
|
||||
Database(&Message{}).Where("service = ?", 0).Limit(10).Find(&message)
|
||||
return message
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ func (c Core) SassVars() string {
|
|||
if !source.UsingAssets(utils.Directory) {
|
||||
return ""
|
||||
}
|
||||
return source.OpenAsset(utils.Directory, "scss/variables.scss")
|
||||
return source.OpenAsset("scss/variables.scss")
|
||||
}
|
||||
|
||||
// BaseSASS is the base design , this opens the file /assets/scss/base.scss to be edited in Theme
|
||||
|
@ -138,7 +138,7 @@ func (c Core) BaseSASS() string {
|
|||
if !source.UsingAssets(utils.Directory) {
|
||||
return ""
|
||||
}
|
||||
return source.OpenAsset(utils.Directory, "scss/base.scss")
|
||||
return source.OpenAsset("scss/base.scss")
|
||||
}
|
||||
|
||||
// MobileSASS is the -webkit responsive custom css designs. This opens the
|
||||
|
@ -147,7 +147,7 @@ func (c Core) MobileSASS() string {
|
|||
if !source.UsingAssets(utils.Directory) {
|
||||
return ""
|
||||
}
|
||||
return source.OpenAsset(utils.Directory, "scss/mobile.scss")
|
||||
return source.OpenAsset("scss/mobile.scss")
|
||||
}
|
||||
|
||||
// AllOnline will be true if all services are online
|
||||
|
@ -171,7 +171,7 @@ func SelectCore() (*Core, error) {
|
|||
log.Errorf("core database has not been setup yet, does not have the 'core' table")
|
||||
return nil, errors.New("core database has not been setup yet.")
|
||||
}
|
||||
db := coreDB().First(&CoreApp)
|
||||
db := Database(&Core{}).First(&CoreApp)
|
||||
if db.Error() != nil {
|
||||
return nil, db.Error()
|
||||
}
|
||||
|
|
|
@ -47,68 +47,42 @@ func init() {
|
|||
// DbConfig stores the config.yml file for the statup configuration
|
||||
type DbConfig types.DbConfig
|
||||
|
||||
// failuresDB returns the 'failures' database column
|
||||
func failuresDB() types.Database {
|
||||
return DbSession.Model(&types.Failure{})
|
||||
}
|
||||
|
||||
// hitsDB returns the 'hits' database column
|
||||
func hitsDB() types.Database {
|
||||
return DbSession.Model(&types.Hit{})
|
||||
}
|
||||
|
||||
// servicesDB returns the 'services' database column
|
||||
func servicesDB() types.Database {
|
||||
return DbSession.Model(&types.Service{})
|
||||
}
|
||||
|
||||
// coreDB returns the single column 'core'
|
||||
func coreDB() types.Database {
|
||||
return DbSession.Table("core").Model(&CoreApp)
|
||||
}
|
||||
|
||||
// usersDB returns the 'users' database column
|
||||
func usersDB() types.Database {
|
||||
return DbSession.Model(&types.User{})
|
||||
}
|
||||
|
||||
// checkinDB returns the Checkin records for a service
|
||||
func checkinDB() types.Database {
|
||||
return DbSession.Model(&types.Checkin{})
|
||||
}
|
||||
|
||||
// checkinHitsDB returns the Checkin Hits records for a service
|
||||
func checkinHitsDB() types.Database {
|
||||
return DbSession.Model(&types.CheckinHit{})
|
||||
}
|
||||
|
||||
// messagesDb returns the Checkin records for a service
|
||||
func messagesDb() types.Database {
|
||||
return DbSession.Model(&types.Message{})
|
||||
}
|
||||
|
||||
// messagesDb returns the Checkin records for a service
|
||||
func groupsDb() types.Database {
|
||||
return DbSession.Model(&types.Group{})
|
||||
}
|
||||
|
||||
// incidentsDB returns the 'incidents' database column
|
||||
func incidentsDB() types.Database {
|
||||
return DbSession.Model(&types.Incident{})
|
||||
}
|
||||
|
||||
// incidentsUpdatesDB returns the 'incidents updates' database column
|
||||
func incidentsUpdatesDB() types.Database {
|
||||
return DbSession.Model(&types.IncidentUpdate{})
|
||||
func Database(obj interface{}) types.Database {
|
||||
switch obj.(type) {
|
||||
case *types.Service, *Service, []*Service:
|
||||
return DbSession.Model(&types.Service{})
|
||||
case *types.Hit, *Hit, []*Hit:
|
||||
return DbSession.Model(&types.Hit{})
|
||||
case *types.Failure, *Failure, []*Failure:
|
||||
return DbSession.Model(&types.Failure{})
|
||||
case *types.Core, *Core:
|
||||
return DbSession.Table("core").Model(&CoreApp)
|
||||
case *types.Checkin, *Checkin, []*Checkin:
|
||||
return DbSession.Model(&types.Checkin{})
|
||||
case *types.CheckinHit, *CheckinHit, []*CheckinHit:
|
||||
return DbSession.Model(&types.CheckinHit{})
|
||||
case *types.User, *User, []*User:
|
||||
return DbSession.Model(&types.User{})
|
||||
case *types.Group, *Group, []*Group:
|
||||
return DbSession.Model(&types.Group{})
|
||||
case *types.Incident, *Incident, []*Incident:
|
||||
return DbSession.Model(&types.Incident{})
|
||||
case *types.IncidentUpdate, *IncidentUpdate, []*IncidentUpdate:
|
||||
return DbSession.Model(&types.IncidentUpdate{})
|
||||
case *types.Message, *Message, []*Message:
|
||||
return DbSession.Model(&types.Message{})
|
||||
default:
|
||||
return DbSession
|
||||
}
|
||||
}
|
||||
|
||||
// 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) 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))
|
||||
return Database(&Hit{}).Select(selector).Where("service = ? AND created_at BETWEEN ? AND ?", s.Id, t1.UTC().Format(types.TIME), t2.UTC().Format(types.TIME))
|
||||
} else {
|
||||
return hitsDB().Select(selector).Where("service = ? AND created_at BETWEEN ? AND ?", s.Id, t1.UTC().Format(types.TIME_DAY), t2.UTC().Format(types.TIME_DAY))
|
||||
return Database(&Hit{}).Select(selector).Where("service = ? AND created_at BETWEEN ? AND ?", s.Id, t1.UTC().Format(types.TIME_DAY), t2.UTC().Format(types.TIME_DAY))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,7 +160,7 @@ func (c *Core) InsertCore(db *types.DbConfig) (*Core, error) {
|
|||
MigrationId: time.Now().Unix(),
|
||||
Config: db,
|
||||
}}
|
||||
query := coreDB().Create(&CoreApp)
|
||||
query := Database(CoreApp).Create(&CoreApp)
|
||||
return CoreApp, query.Error()
|
||||
}
|
||||
|
||||
|
@ -345,7 +319,7 @@ func (c *Core) CreateCore() *Core {
|
|||
Domain: c.Domain,
|
||||
MigrationId: time.Now().Unix(),
|
||||
}
|
||||
db := coreDB().Create(&newCore)
|
||||
db := Database(newCore).Create(&newCore)
|
||||
if db.Error() == nil {
|
||||
CoreApp = &Core{Core: newCore}
|
||||
}
|
||||
|
@ -409,7 +383,7 @@ func (c *Core) MigrateDatabase() error {
|
|||
}
|
||||
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))
|
||||
log.Errorln(fmt.Sprintf("Statping Database could not be migrated: %v", tx.Error()))
|
||||
return tx.Error()
|
||||
}
|
||||
log.Infoln("Statping Database Migrated")
|
||||
|
|
|
@ -37,7 +37,7 @@ const (
|
|||
// CreateFailure will create a new Failure record for a service
|
||||
func (s *Service) CreateFailure(f *types.Failure) (int64, error) {
|
||||
f.Service = s.Id
|
||||
row := failuresDB().Create(f)
|
||||
row := Database(&types.Failure{}).Create(f)
|
||||
if row.Error() != nil {
|
||||
log.Errorln(row.Error())
|
||||
return 0, row.Error()
|
||||
|
@ -62,7 +62,7 @@ func (s *Service) AllFailures() []types.Failure {
|
|||
}
|
||||
|
||||
func (s *Service) FailuresDb(r *http.Request) types.Database {
|
||||
return failuresDB().Where("service = ?", s.Id).QuerySearch(r).Order("id desc")
|
||||
return Database(&types.Failure{}).Where("service = ?", s.Id).QuerySearch(r).Order("id desc")
|
||||
}
|
||||
|
||||
// DeleteFailures will delete all failures for a service
|
||||
|
@ -77,14 +77,14 @@ func (s *Service) DeleteFailures() {
|
|||
// LimitedFailures will return the last amount of failures from a service
|
||||
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)
|
||||
Database(&types.Failure{}).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 int) []*Failure {
|
||||
var failArr []*Failure
|
||||
failuresDB().Where("service = ?", s.Id).Where("method = 'checkin'").Order("id desc").Limit(amount).Find(&failArr)
|
||||
Database(&types.Failure{}).Where("service = ?", s.Id).Where("method = 'checkin'").Order("id desc").Limit(amount).Find(&failArr)
|
||||
return failArr
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,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)
|
||||
db := Database(&types.Failure{}).Delete(f)
|
||||
return db.Error()
|
||||
}
|
||||
|
||||
|
@ -119,9 +119,9 @@ func (c *Core) Count24HFailures() uint64 {
|
|||
// CountFailures returns the total count of failures for all services
|
||||
func CountFailures() uint64 {
|
||||
var count uint64
|
||||
err := failuresDB().Count(&count)
|
||||
err := Database(&types.Failure{}).Count(&count)
|
||||
if err.Error() != nil {
|
||||
log.Warnln(err.Error)
|
||||
log.Warnln(err.Error())
|
||||
return 0
|
||||
}
|
||||
return count
|
||||
|
@ -132,7 +132,7 @@ func (s *Service) TotalFailuresOnDate(ago time.Time) (uint64, error) {
|
|||
var count uint64
|
||||
date := ago.UTC().Format("2006-01-02 00:00:00")
|
||||
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'")
|
||||
rows := Database(&types.Failure{}).Where("service = ? AND created_at BETWEEN ? AND ?", s.Id, date, dateend).Not("method = 'checkin'")
|
||||
err := rows.Count(&count)
|
||||
return count, err.Error()
|
||||
}
|
||||
|
@ -146,7 +146,7 @@ func (s *Service) TotalFailures24() (uint64, error) {
|
|||
// TotalFailures returns the total amount of failures for a service
|
||||
func (s *Service) TotalFailures() (uint64, error) {
|
||||
var count uint64
|
||||
rows := failuresDB().Where("service = ?", s.Id)
|
||||
rows := Database(&types.Failure{}).Where("service = ?", s.Id)
|
||||
err := rows.Count(&count)
|
||||
return count, err.Error()
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ func (s *Service) FailuresDaysAgo(days int) uint64 {
|
|||
// TotalFailuresSince returns the total amount of failures for a service since a specific time/date
|
||||
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'")
|
||||
rows := Database(&types.Failure{}).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()
|
||||
}
|
||||
|
|
|
@ -16,21 +16,21 @@ func (g *Group) Delete() error {
|
|||
s.GroupId = 0
|
||||
s.Update(false)
|
||||
}
|
||||
err := groupsDb().Delete(g)
|
||||
err := Database(&Group{}).Delete(g)
|
||||
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)
|
||||
db := Database(&Group{}).Create(g)
|
||||
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)
|
||||
db := Database(&Group{}).Update(g)
|
||||
return g.Id, db.Error()
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ func (g *Group) VisibleServices(auth bool) []*Service {
|
|||
func SelectGroups(includeAll bool, auth bool) []*Group {
|
||||
var groups []*Group
|
||||
var validGroups []*Group
|
||||
groupsDb().Find(&groups).Order("order_id desc")
|
||||
Database(&Group{}).Find(&groups).Order("order_id desc")
|
||||
for _, g := range groups {
|
||||
if !g.Public.Bool {
|
||||
if auth {
|
||||
|
|
18
core/hits.go
18
core/hits.go
|
@ -27,7 +27,7 @@ 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)
|
||||
db := Database(&types.Hit{}).Create(&h)
|
||||
if db.Error() != nil {
|
||||
log.Errorln(db.Error())
|
||||
return 0, db.Error()
|
||||
|
@ -38,7 +38,7 @@ func (s *Service) CreateHit(h *types.Hit) (int64, error) {
|
|||
// CountHits returns a int64 for all hits for a service
|
||||
func (s *Service) CountHits() (int64, error) {
|
||||
var hits int64
|
||||
col := hitsDB().Where("service = ?", s.Id)
|
||||
col := Database(&types.Hit{}).Where("service = ?", s.Id)
|
||||
err := col.Count(&hits)
|
||||
return hits, err.Error()
|
||||
}
|
||||
|
@ -46,19 +46,19 @@ func (s *Service) CountHits() (int64, 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")
|
||||
col := Database(&types.Hit{}).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")
|
||||
return Database(&types.Hit{}).Where("service = ?", s.Id).QuerySearch(r).Order("id desc")
|
||||
}
|
||||
|
||||
// Hits returns all successful hits for a service
|
||||
func (s *Service) Hits() ([]*types.Hit, error) {
|
||||
var hits []*types.Hit
|
||||
col := hitsDB().Where("service = ?", s.Id).Order("id desc")
|
||||
col := Database(&types.Hit{}).Where("service = ?", s.Id).Order("id desc")
|
||||
err := col.Find(&hits)
|
||||
return hits, err.Error()
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ func (s *Service) Hits() ([]*types.Hit, error) {
|
|||
// LimitedHits returns the last 1024 successful/online 'hit' records for a service
|
||||
func (s *Service) LimitedHits(amount int) ([]*types.Hit, error) {
|
||||
var hits []*types.Hit
|
||||
col := hitsDB().Where("service = ?", s.Id).Order("id desc").Limit(amount)
|
||||
col := Database(&types.Hit{}).Where("service = ?", s.Id).Order("id desc").Limit(amount)
|
||||
err := col.Find(&hits)
|
||||
return reverseHits(hits), err.Error()
|
||||
}
|
||||
|
@ -82,21 +82,21 @@ func reverseHits(input []*types.Hit) []*types.Hit {
|
|||
// TotalHits returns the total amount of successful hits a service has
|
||||
func (s *Service) TotalHits() (uint64, error) {
|
||||
var count uint64
|
||||
col := hitsDB().Where("service = ?", s.Id).Count(&count)
|
||||
col := Database(&types.Hit{}).Where("service = ?", s.Id).Count(&count)
|
||||
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)
|
||||
rows := Database(&types.Hit{}).Where("service = ? AND created_at > ?", s.Id, ago.UTC().Format("2006-01-02 15:04:05")).Count(&count)
|
||||
return count, rows.Error()
|
||||
}
|
||||
|
||||
// Sum returns the added value Latency for all of the services successful hits.
|
||||
func (s *Service) Sum() float64 {
|
||||
var sum float64
|
||||
rows, _ := hitsDB().Where("service = ?", s.Id).Select("sum(latency) as total").Rows()
|
||||
rows, _ := Database(&types.Hit{}).Where("service = ?", s.Id).Select("sum(latency) as total").Rows()
|
||||
for rows.Next() {
|
||||
rows.Scan(&sum)
|
||||
}
|
||||
|
|
|
@ -21,17 +21,17 @@ func ReturnIncident(u *types.Incident) *Incident {
|
|||
// SelectIncident returns the Incident based on the Incident's ID.
|
||||
func SelectIncident(id int64) (*Incident, error) {
|
||||
var incident Incident
|
||||
err := incidentsDB().Where("id = ?", id).First(&incident)
|
||||
err := Database(incident).Where("id = ?", id).First(&incident)
|
||||
return &incident, err.Error()
|
||||
}
|
||||
|
||||
// AllIncidents will return all incidents and updates recorded
|
||||
func AllIncidents() []*Incident {
|
||||
var incidents []*Incident
|
||||
incidentsDB().Find(&incidents).Order("id desc")
|
||||
Database(incidents).Find(&incidents).Order("id desc")
|
||||
for _, i := range incidents {
|
||||
var updates []*types.IncidentUpdate
|
||||
incidentsUpdatesDB().Find(&updates).Order("id desc")
|
||||
Database(updates).Find(&updates).Order("id desc")
|
||||
i.Updates = updates
|
||||
}
|
||||
return incidents
|
||||
|
@ -40,46 +40,46 @@ func AllIncidents() []*Incident {
|
|||
// Incidents will return the all incidents for a service
|
||||
func (s *Service) Incidents() []*Incident {
|
||||
var incidentArr []*Incident
|
||||
incidentsDB().Where("service = ?", s.Id).Order("id desc").Find(&incidentArr)
|
||||
Database(incidentArr).Where("service = ?", s.Id).Order("id desc").Find(&incidentArr)
|
||||
return incidentArr
|
||||
}
|
||||
|
||||
// AllUpdates will return the all updates for an incident
|
||||
func (i *Incident) AllUpdates() []*IncidentUpdate {
|
||||
var updatesArr []*IncidentUpdate
|
||||
incidentsUpdatesDB().Where("incident = ?", i.Id).Order("id desc").Find(&updatesArr)
|
||||
Database(updatesArr).Where("incident = ?", i.Id).Order("id desc").Find(&updatesArr)
|
||||
return updatesArr
|
||||
}
|
||||
|
||||
// Delete will remove a incident
|
||||
func (i *Incident) Delete() error {
|
||||
err := incidentsDB().Delete(i)
|
||||
err := Database(i).Delete(i)
|
||||
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)
|
||||
db := Database(i).Create(i)
|
||||
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)
|
||||
db := Database(i).Update(i)
|
||||
return i.Id, db.Error()
|
||||
}
|
||||
|
||||
// Delete will remove a incident update
|
||||
func (i *IncidentUpdate) Delete() error {
|
||||
err := incidentsUpdatesDB().Delete(i)
|
||||
err := Database(i).Delete(i)
|
||||
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)
|
||||
db := Database(i).Create(i)
|
||||
return i.Id, db.Error()
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
)
|
||||
|
||||
func TestCsvFileIntegration(t *testing.T) {
|
||||
data, err := ioutil.ReadFile("../../source/tmpl/bulk_import.csv")
|
||||
data, err := ioutil.ReadFile("testdata/bulk_import.csv")
|
||||
require.Nil(t, err)
|
||||
|
||||
t.Run("Set Field Value", func(t *testing.T) {
|
||||
|
|
|
@ -8,6 +8,8 @@ import (
|
|||
|
||||
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"}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package integrations
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIntegrations(t *testing.T) {
|
||||
|
||||
t.Run("Collect Integrations", func(t *testing.T) {
|
||||
amount := len(Integrations)
|
||||
assert.Equal(t, 3, amount)
|
||||
})
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
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
|
|
|
@ -8,15 +8,15 @@ import (
|
|||
|
||||
func TestTraefikIntegration(t *testing.T) {
|
||||
|
||||
t.SkipNow()
|
||||
|
||||
t.Run("List Services from Traefik", func(t *testing.T) {
|
||||
t.SkipNow()
|
||||
services, err := TraefikIntegrator.List()
|
||||
require.Nil(t, err)
|
||||
assert.NotEqual(t, 0, len(services))
|
||||
})
|
||||
|
||||
t.Run("Confirm Services from Traefik", func(t *testing.T) {
|
||||
t.SkipNow()
|
||||
services, err := TraefikIntegrator.List()
|
||||
require.Nil(t, err)
|
||||
for _, s := range services {
|
||||
|
|
|
@ -28,7 +28,7 @@ type Message struct {
|
|||
// SelectServiceMessages returns all messages for a service
|
||||
func SelectServiceMessages(id int64) []*Message {
|
||||
var message []*Message
|
||||
messagesDb().Where("service = ?", id).Limit(10).Find(&message)
|
||||
Database(&Message{}).Where("service = ?", id).Limit(10).Find(&message)
|
||||
return message
|
||||
}
|
||||
|
||||
|
@ -40,14 +40,14 @@ func ReturnMessage(m *types.Message) *Message {
|
|||
// SelectMessages returns all messages
|
||||
func SelectMessages() ([]*Message, error) {
|
||||
var messages []*Message
|
||||
db := messagesDb().Find(&messages).Order("id desc")
|
||||
db := Database(&Message{}).Find(&messages).Order("id desc")
|
||||
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)
|
||||
db := Database(&Message{}).Where("id = ?", id).Find(&message)
|
||||
return &message, db.Error()
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ func (m *Message) Service() *Service {
|
|||
// Create will create a Message and insert it into the database
|
||||
func (m *Message) Create() (int64, error) {
|
||||
m.CreatedAt = time.Now().UTC()
|
||||
db := messagesDb().Create(m)
|
||||
db := Database(&Message{}).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()
|
||||
|
@ -71,13 +71,13 @@ func (m *Message) Create() (int64, error) {
|
|||
|
||||
// Delete will delete a Message from database
|
||||
func (m *Message) Delete() error {
|
||||
db := messagesDb().Delete(m)
|
||||
db := Database(&Message{}).Delete(m)
|
||||
return db.Error()
|
||||
}
|
||||
|
||||
// Update will update a Message in the database
|
||||
func (m *Message) Update() (*Message, error) {
|
||||
db := messagesDb().Update(m)
|
||||
db := Database(&Message{}).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()
|
||||
|
|
|
@ -93,8 +93,8 @@ type NotificationLog struct {
|
|||
|
||||
// AfterFind for Notification will set the timezone
|
||||
func (n *Notification) AfterFind() (err error) {
|
||||
n.CreatedAt = utils.Timezoner(n.CreatedAt, timezone)
|
||||
n.UpdatedAt = utils.Timezoner(n.UpdatedAt, timezone)
|
||||
n.CreatedAt = utils.Now()
|
||||
n.UpdatedAt = utils.Now()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -116,9 +116,8 @@ func modelDb(n *Notification) types.Database {
|
|||
}
|
||||
|
||||
// SetDB is called by core to inject the database for a notifier to use
|
||||
func SetDB(d types.Database, zone float32) {
|
||||
func SetDB(d types.Database) {
|
||||
db = d
|
||||
timezone = zone
|
||||
}
|
||||
|
||||
// asNotification accepts a Notifier and returns a Notification struct
|
||||
|
@ -247,8 +246,8 @@ func Init(n Notifier) (*Notification, error) {
|
|||
var notify *Notification
|
||||
if err == nil {
|
||||
notify, _ = SelectNotification(n)
|
||||
notify.CreatedAt = utils.Timezoner(notify.CreatedAt, timezone)
|
||||
notify.UpdatedAt = utils.Timezoner(notify.UpdatedAt, timezone)
|
||||
notify.CreatedAt = time.Now().UTC()
|
||||
notify.UpdatedAt = time.Now().UTC()
|
||||
if notify.Delay.Seconds() == 0 {
|
||||
notify.Delay = time.Duration(1 * time.Second)
|
||||
}
|
||||
|
@ -350,7 +349,7 @@ func (n *Notification) SentLastMinute() int {
|
|||
func (n *Notification) SentLast(since time.Time) int {
|
||||
sent := 0
|
||||
for _, v := range n.Logs() {
|
||||
lastTime := time.Time(v.Time)
|
||||
lastTime := time.Time(v.Time).UTC()
|
||||
if lastTime.After(since) {
|
||||
sent++
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import (
|
|||
"fmt"
|
||||
"github.com/hunterlong/statping/types"
|
||||
"github.com/hunterlong/statping/utils"
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
|
@ -56,19 +55,20 @@ var core = &types.Core{
|
|||
}
|
||||
|
||||
func injectDatabase() {
|
||||
utils.DeleteFile(dir + "/notifier.db")
|
||||
db, _ = gorm.Open("sqlite3", dir+"/notifier.db")
|
||||
sqlPath := dir + "/notifier.db"
|
||||
utils.DeleteFile(sqlPath)
|
||||
db, _ = types.Openw("sqlite3", sqlPath)
|
||||
db.CreateTable(&Notification{})
|
||||
}
|
||||
|
||||
func TestIsBasicType(t *testing.T) {
|
||||
assert.True(t, isType(example, new(Notifier)))
|
||||
assert.True(t, isType(example, new(BasicEvents)))
|
||||
assert.True(t, isType(example, new(ServiceEvents)))
|
||||
assert.True(t, isType(example, new(UserEvents)))
|
||||
assert.True(t, isType(example, new(CoreEvents)))
|
||||
assert.True(t, isType(example, new(NotifierEvents)))
|
||||
assert.True(t, isType(example, new(Tester)))
|
||||
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(CoreEvents)))
|
||||
assert.True(t, utils.IsType(example, new(NotifierEvents)))
|
||||
assert.True(t, utils.IsType(example, new(Tester)))
|
||||
}
|
||||
|
||||
func TestIsInDatabase(t *testing.T) {
|
||||
|
|
|
@ -207,7 +207,7 @@ func insertSampleCheckins() error {
|
|||
|
||||
// InsertSampleHits will create a couple new hits for the sample services
|
||||
func InsertSampleHits() error {
|
||||
tx := hitsDB().Begin()
|
||||
tx := Database(&Hit{}).Begin()
|
||||
sg := new(sync.WaitGroup)
|
||||
for i := int64(1); i <= 5; i++ {
|
||||
sg.Add(1)
|
||||
|
@ -250,7 +250,7 @@ func insertSampleCore() error {
|
|||
CreatedAt: time.Now().UTC(),
|
||||
UseCdn: types.NewNullBool(false),
|
||||
}
|
||||
query := coreDB().Create(core)
|
||||
query := Database(&Core{}).Create(core)
|
||||
return query.Error()
|
||||
}
|
||||
|
||||
|
@ -510,6 +510,7 @@ func TmpRecords(dbFile string) error {
|
|||
var err error
|
||||
CoreApp = NewCore()
|
||||
CoreApp.Name = "Tester"
|
||||
CoreApp.Setup = true
|
||||
configs := &types.DbConfig{
|
||||
DbConn: "sqlite",
|
||||
Project: "Tester",
|
||||
|
|
|
@ -103,14 +103,14 @@ func (s *Service) CheckinProcess() {
|
|||
// AllCheckins will return a slice of AllCheckins for a Service
|
||||
func (s *Service) AllCheckins() []*Checkin {
|
||||
var checkin []*Checkin
|
||||
checkinDB().Where("service = ?", s.Id).Find(&checkin)
|
||||
Database(&Checkin{}).Where("service = ?", s.Id).Find(&checkin)
|
||||
return checkin
|
||||
}
|
||||
|
||||
// SelectAllServices returns a slice of *core.Service to be store on []*core.Services, should only be called once on startup.
|
||||
func (c *Core) SelectAllServices(start bool) ([]*Service, error) {
|
||||
var services []*Service
|
||||
db := servicesDB().Find(&services).Order("order_id desc")
|
||||
db := Database(&Service{}).Find(&services).Order("order_id desc")
|
||||
if db.Error() != nil {
|
||||
log.Errorln(fmt.Sprintf("service error: %v", db.Error()))
|
||||
return nil, db.Error()
|
||||
|
@ -354,9 +354,9 @@ func updateService(s *Service) {
|
|||
// Delete will remove a service from the database, it will also end the service checking go routine
|
||||
func (s *Service) Delete() error {
|
||||
i := s.index()
|
||||
err := servicesDB().Delete(s)
|
||||
err := Database(&Service{}).Delete(s)
|
||||
if err.Error() != nil {
|
||||
log.Errorln(fmt.Sprintf("Failed to delete service %v. %v", s.Name, err.Error))
|
||||
log.Errorln(fmt.Sprintf("Failed to delete service %v. %v", s.Name, err.Error()))
|
||||
return err.Error()
|
||||
}
|
||||
s.Close()
|
||||
|
@ -369,7 +369,7 @@ func (s *Service) Delete() 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)
|
||||
err := Database(&Service{}).Update(&s)
|
||||
if err.Error() != nil {
|
||||
log.Errorln(fmt.Sprintf("Failed to update service %v. %v", s.Name, err))
|
||||
return err.Error()
|
||||
|
@ -396,7 +396,7 @@ func (s *Service) Update(restart bool) 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)
|
||||
db := Database(&Service{}).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()
|
||||
|
|
|
@ -35,35 +35,35 @@ func ReturnUser(u *types.User) *User {
|
|||
// CountUsers returns the amount of users
|
||||
func CountUsers() int64 {
|
||||
var amount int64
|
||||
usersDB().Count(&amount)
|
||||
Database(&User{}).Count(&amount)
|
||||
return amount
|
||||
}
|
||||
|
||||
// SelectUser returns the User based on the User's ID.
|
||||
func SelectUser(id int64) (*User, error) {
|
||||
var user User
|
||||
err := usersDB().Where("id = ?", id).First(&user)
|
||||
err := Database(&User{}).Where("id = ?", id).First(&user)
|
||||
return &user, err.Error()
|
||||
}
|
||||
|
||||
// SelectUsername returns the User based on the User's username
|
||||
func SelectUsername(username string) (*User, error) {
|
||||
var user User
|
||||
res := usersDB().Where("username = ?", username)
|
||||
res := Database(&User{}).Where("username = ?", username)
|
||||
err := res.First(&user)
|
||||
return &user, err.Error()
|
||||
}
|
||||
|
||||
// Delete will remove the User record from the database
|
||||
func (u *User) Delete() error {
|
||||
return usersDB().Delete(u).Error()
|
||||
return Database(&User{}).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 Database(&User{}).Update(u).Error()
|
||||
}
|
||||
|
||||
// Create will insert a new User into the database
|
||||
|
@ -72,7 +72,7 @@ func (u *User) Create() (int64, error) {
|
|||
u.Password = utils.HashPassword(u.Password)
|
||||
u.ApiKey = utils.NewSHA1Hash(5)
|
||||
u.ApiSecret = utils.NewSHA1Hash(10)
|
||||
db := usersDB().Create(u)
|
||||
db := Database(&User{}).Create(u)
|
||||
if db.Error() != nil {
|
||||
return 0, db.Error()
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ func (u *User) Create() (int64, error) {
|
|||
// SelectAllUsers returns all users
|
||||
func SelectAllUsers() ([]*User, error) {
|
||||
var users []*User
|
||||
db := usersDB().Find(&users)
|
||||
db := Database(&User{}).Find(&users)
|
||||
if db.Error() != nil {
|
||||
log.Errorln(fmt.Sprintf("Failed to load all users. %v", db.Error()))
|
||||
return nil, db.Error()
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||
const HtmlPlugin = require('html-webpack-plugin');
|
||||
const MiniCSSExtractPlugin = require('mini-css-extract-plugin');
|
||||
const helpers = require('./helpers');
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
@ -60,8 +59,7 @@ const webpackConfig = {
|
|||
]
|
||||
},
|
||||
plugins: [
|
||||
new VueLoaderPlugin(),
|
||||
new HtmlPlugin({ template: 'public/index.html', chunksSortMode: 'dependency' })
|
||||
new VueLoaderPlugin()
|
||||
]
|
||||
};
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const HtmlPlugin = require('html-webpack-plugin');
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin');
|
||||
const helpers = require('./helpers');
|
||||
const commonConfig = require('./webpack.config.common');
|
||||
|
@ -25,7 +26,11 @@ const webpackConfig = merge(commonConfig, {
|
|||
plugins: [
|
||||
new webpack.EnvironmentPlugin(environment),
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new FriendlyErrorsPlugin()
|
||||
new FriendlyErrorsPlugin(),
|
||||
new HtmlPlugin({
|
||||
template: 'public/index.html',
|
||||
chunksSortMode: 'dependency'
|
||||
})
|
||||
],
|
||||
devServer: {
|
||||
compress: true,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const HtmlPlugin = require('html-webpack-plugin');
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const MiniCSSExtractPlugin = require('mini-css-extract-plugin');
|
||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
||||
|
@ -48,7 +49,7 @@ const webpackConfig = merge(commonConfig, {
|
|||
},
|
||||
styles: {
|
||||
test: /\.css$/,
|
||||
name: 'styles',
|
||||
name: 'style',
|
||||
chunks: 'all',
|
||||
enforce: true
|
||||
}
|
||||
|
@ -59,7 +60,7 @@ const webpackConfig = merge(commonConfig, {
|
|||
new webpack.EnvironmentPlugin(environment),
|
||||
new MiniCSSExtractPlugin({
|
||||
filename: 'css/[name].css',
|
||||
chunkFilename: 'css/[name].[hash].css'
|
||||
chunkFilename: 'css/[name].css'
|
||||
}),
|
||||
new CompressionPlugin({
|
||||
filename: '[path].gz[query]',
|
||||
|
@ -68,7 +69,13 @@ const webpackConfig = merge(commonConfig, {
|
|||
threshold: 10240,
|
||||
minRatio: 0.8
|
||||
}),
|
||||
new webpack.HashedModuleIdsPlugin()
|
||||
new webpack.HashedModuleIdsPlugin(),
|
||||
new HtmlPlugin({
|
||||
template: 'public/base.gohtml',
|
||||
filename: 'base.gohtml',
|
||||
inject: false,
|
||||
minify: false
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
|
|
|
@ -4,12 +4,11 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "rm -rf dist && cross-env NODE_ENV=production webpack",
|
||||
"build": "rm -rf dist && cross-env NODE_ENV=production webpack --mode production",
|
||||
"dev": "cross-env NODE_ENV=development webpack-dev-server --host 0.0.0.0 --port 8888 --progress",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "~7.2",
|
||||
"@fortawesome/fontawesome-free-solid": "^5.1.0-3",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.26",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.12.0",
|
||||
|
@ -37,6 +36,7 @@
|
|||
"@babel/plugin-proposal-json-strings": "~7.2",
|
||||
"@babel/plugin-syntax-dynamic-import": "~7.2",
|
||||
"@babel/plugin-syntax-import-meta": "~7.2",
|
||||
"@babel/polyfill": "~7.2",
|
||||
"@babel/preset-env": "~7.8.3",
|
||||
"@vue/babel-preset-app": "^4.1.2",
|
||||
"@vue/cli-plugin-babel": "^4.1.0",
|
||||
|
@ -57,7 +57,7 @@
|
|||
"eslint-plugin-vue": "~5.1",
|
||||
"file-loader": "^5.0.2",
|
||||
"friendly-errors-webpack-plugin": "~1.7",
|
||||
"html-webpack-plugin": "~3.2",
|
||||
"html-webpack-plugin": "^4.0.0-beta.11",
|
||||
"mini-css-extract-plugin": "~0.5",
|
||||
"node-sass": "^4.13.1",
|
||||
"optimize-css-assets-webpack-plugin": "~5.0",
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
{{ define "base" }}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{Name}}</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, maximum-scale=1.0, user-scalable=0">
|
||||
<meta name="description" content="{{Description}}">
|
||||
<base href="{{BasePath}}">
|
||||
{{if USE_CDN}}
|
||||
<link rel="shortcut icon" type="image/x-icon" href="https://assets.statping.com/favicon.ico">
|
||||
{{else}}
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
|
||||
<% _.each(htmlWebpackPlugin.tags.headTags, function(headTag) { %>
|
||||
<%= headTag %> <% }) %>
|
||||
{{end}}
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but Statping doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
|
||||
<div id="app"></div>
|
||||
|
||||
{{if USE_CDN}}
|
||||
|
||||
{{else}}
|
||||
<% _.each(htmlWebpackPlugin.tags.bodyTags, function(bodyTag) { %>
|
||||
<%= bodyTag %> <% }) %>
|
||||
{{end}}
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div class="list-group mt-3 mb-4">
|
||||
|
||||
<div v-for="(failure, index) in failures" :key="index" class="mb-2 list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">{{failure.issue}}</h5>
|
||||
<small>{{toLocal(failure.created_at)}}</small>
|
||||
</div>
|
||||
<p class="mb-1">{{failure.issue}}</p>
|
||||
</div>
|
||||
|
||||
<nav aria-label="Page navigation example">
|
||||
<ul class="pagination">
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#" aria-label="Previous">
|
||||
<span aria-hidden="true">«</span>
|
||||
<span class="sr-only">Previous</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item"><a class="page-link" href="#">1</a></li>
|
||||
<li class="page-item"><a class="page-link" href="#">2</a></li>
|
||||
<li class="page-item"><a class="page-link" href="#">3</a></li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#" aria-label="Next">
|
||||
<span aria-hidden="true">»</span>
|
||||
<span class="sr-only">Next</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ServiceChart from "./ServiceChart";
|
||||
import Api from "../API";
|
||||
|
||||
export default {
|
||||
name: 'ServiceFailures',
|
||||
components: {ServiceChart},
|
||||
props: {
|
||||
service: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
failures: [],
|
||||
limit: 15,
|
||||
offset: 0,
|
||||
}
|
||||
},
|
||||
async mounted () {
|
||||
this.failures = await Api.service_failures(this.service.id, this.now(), this.now(), this.limit, this.offset)
|
||||
},
|
||||
methods: {
|
||||
smallText(s) {
|
||||
if (s.online) {
|
||||
return `Online, last checked ${this.ago(s.last_success)}`
|
||||
} else {
|
||||
return `Offline, last error: ${s.last_failure.issue} ${this.ago(s.last_failure.created_at)}`
|
||||
}
|
||||
},
|
||||
ago(t1) {
|
||||
const tm = this.parseTime(t1)
|
||||
return this.duration(this.$moment().utc(), tm)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
|
@ -0,0 +1,70 @@
|
|||
<template>
|
||||
<form @submit.prevent="login">
|
||||
<div class="form-group row">
|
||||
<label for="username" class="col-sm-2 col-form-label">Username</label>
|
||||
<div class="col-sm-10">
|
||||
<input @keyup="checkForm" type="text" v-model="username" name="username" class="form-control" id="username" placeholder="Username" autocorrect="off" autocapitalize="none">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-sm-2 col-form-label">Password</label>
|
||||
<div class="col-sm-10">
|
||||
<input @keyup="checkForm" type="password" v-model="password" name="password" class="form-control" id="password" placeholder="Password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-12">
|
||||
<div v-if="error" class="alert alert-danger" role="alert">
|
||||
Incorrect username or password
|
||||
</div>
|
||||
<button @click.prevent="login" type="submit" class="btn btn-block mb-3 btn-primary" :disabled="disabled || loading">
|
||||
{{loading ? "Loading" : "Sign in"}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Api from "../components/API";
|
||||
|
||||
export default {
|
||||
name: 'FormLogin',
|
||||
data () {
|
||||
return {
|
||||
username: "",
|
||||
password: "",
|
||||
auth: {},
|
||||
loading: false,
|
||||
error: false,
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
checkForm() {
|
||||
if (!this.username || !this.password) {
|
||||
this.disabled = true
|
||||
} else {
|
||||
this.disabled = false
|
||||
}
|
||||
},
|
||||
async login () {
|
||||
this.loading = true
|
||||
this.error = false
|
||||
const auth = await Api.login(this.username, this.password)
|
||||
if (auth.error) {
|
||||
this.error = true
|
||||
} else if (auth.token) {
|
||||
this.auth = Api.saveToken(this.username, auth.token)
|
||||
await this.$store.dispatch('loadAdmin')
|
||||
this.$router.push('/dashboard')
|
||||
}
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
</style>
|
|
@ -41,13 +41,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="notify_method" class="col-sm-4 col-form-label">Notification Method</label>
|
||||
<div class="col-sm-8">
|
||||
<input v-model="message.notify_method" type="text" name="notify_method" class="form-control" id="notify_method" value="" placeholder="email">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="notify_method" class="col-sm-4 col-form-label">Notify Users</label>
|
||||
<div class="col-sm-8">
|
||||
|
@ -58,7 +51,14 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<div v-if="message.notify" class="form-group row">
|
||||
<label for="notify_method" class="col-sm-4 col-form-label">Notification Method</label>
|
||||
<div class="col-sm-8">
|
||||
<input v-model="message.notify_method" type="text" name="notify_method" class="form-control" id="notify_method" value="" placeholder="email">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="message.notify" class="form-group row">
|
||||
<label for="notify_before" class="col-sm-4 col-form-label">Notify Before</label>
|
||||
<div class="col-sm-8">
|
||||
<div class="form-inline">
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<div class="col-6">
|
||||
<div class="form-group">
|
||||
<label>Database Connection</label>
|
||||
<select v-model="setup.db_connection" class="form-control">
|
||||
<select @change="canSubmit" v-model="setup.db_connection" class="form-control">
|
||||
<option value="sqlite">Sqlite</option>
|
||||
<option value="postgres">Postgres</option>
|
||||
<option value="mysql">MySQL</option>
|
||||
|
@ -19,23 +19,23 @@
|
|||
</div>
|
||||
<div v-if="setup.db_connection !== 'sqlite'" class="form-group" id="db_host">
|
||||
<label>Host</label>
|
||||
<input v-model="setup.db_host" type="text" class="form-control" placeholder="localhost">
|
||||
<input @keyup="canSubmit" v-model="setup.db_host" type="text" class="form-control" placeholder="localhost">
|
||||
</div>
|
||||
<div v-if="setup.db_connection !== 'sqlite'" class="form-group" id="db_port">
|
||||
<label>Database Port</label>
|
||||
<input v-model="setup.db_port" type="text" class="form-control" placeholder="localhost">
|
||||
<input @keyup="canSubmit" v-model="setup.db_port" type="text" class="form-control" placeholder="localhost">
|
||||
</div>
|
||||
<div v-if="setup.db_connection !== 'sqlite'" class="form-group" id="db_user">
|
||||
<label>Username</label>
|
||||
<input v-model="setup.db_user" type="text" class="form-control" placeholder="root">
|
||||
<input @keyup="canSubmit" v-model="setup.db_user" type="text" class="form-control" placeholder="root">
|
||||
</div>
|
||||
<div v-if="setup.db_connection !== 'sqlite'" class="form-group" id="db_password">
|
||||
<label for="db_password">Password</label>
|
||||
<input v-model="setup.db_password" type="password" class="form-control" placeholder="password123">
|
||||
<input @keyup="canSubmit" v-model="setup.db_password" type="password" class="form-control" placeholder="password123">
|
||||
</div>
|
||||
<div v-if="setup.db_connection !== 'sqlite'" class="form-group" id="db_database">
|
||||
<label for="db_database">Database</label>
|
||||
<input v-model="setup.db_database" type="text" class="form-control" placeholder="Database name">
|
||||
<input @keyup="canSubmit" v-model="setup.db_database" type="text" class="form-control" placeholder="Database name">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -44,37 +44,37 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label>Project Name</label>
|
||||
<input v-model="setup.project" type="text" class="form-control" placeholder="Great Uptime" required>
|
||||
<input @keyup="canSubmit" v-model="setup.project" type="text" class="form-control" placeholder="Great Uptime" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Project Description</label>
|
||||
<input v-model="setup.description" type="text" class="form-control" placeholder="Great Uptime">
|
||||
<input @keyup="canSubmit" v-model="setup.description" type="text" class="form-control" placeholder="Great Uptime">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="domain_input">Domain URL</label>
|
||||
<input v-model="setup.domain" type="text" class="form-control" id="domain_input" required>
|
||||
<input @keyup="canSubmit" v-model="setup.domain" type="text" class="form-control" id="domain_input" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Admin Username</label>
|
||||
<input v-model="setup.username" type="text" class="form-control" placeholder="admin" required>
|
||||
<input @keyup="canSubmit" v-model="setup.username" type="text" class="form-control" placeholder="admin" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Admin Password</label>
|
||||
<input v-model="setup.password" type="password" class="form-control" placeholder="password" required>
|
||||
<input @keyup="canSubmit" v-model="setup.password" type="password" class="form-control" placeholder="password" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Confirm Admin Password</label>
|
||||
<input v-model="setup.confirm_password" type="password" class="form-control" placeholder="password" required>
|
||||
<input @keyup="canSubmit" v-model="setup.confirm_password" type="password" class="form-control" placeholder="password" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<span class="switch">
|
||||
<input v-model="setup.sample_data" type="checkbox" class="switch" id="switch-normal">
|
||||
<input @keyup="canSubmit" v-model="setup.sample_data" type="checkbox" class="switch" id="switch-normal">
|
||||
<label for="switch-normal">Load Sample Data</label>
|
||||
</span>
|
||||
</div>
|
||||
|
@ -85,7 +85,7 @@
|
|||
{{error}}
|
||||
</div>
|
||||
|
||||
<button @click.prevent="saveSetup" v-bind:disabled="canSubmit() && loading" type="submit" class="btn btn-primary btn-block" :class="{'btn-primary': !loading, 'btn-default': loading}">
|
||||
<button @click.prevent="saveSetup" v-bind:disabled="disabled || loading" type="submit" class="btn btn-primary btn-block" :class="{'btn-primary': !loading, 'btn-default': loading}">
|
||||
{{loading ? "Loading..." : "Save Settings"}}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -105,6 +105,7 @@
|
|||
return {
|
||||
error: null,
|
||||
loading: false,
|
||||
disabled: true,
|
||||
setup: {
|
||||
db_connection: "sqlite",
|
||||
db_host: "",
|
||||
|
@ -128,7 +129,7 @@
|
|||
if (!this.$store.getters.hasPublicData) {
|
||||
await this.$store.dispatch('loadRequired')
|
||||
}
|
||||
this.$router.push('/')
|
||||
this.$router.push('/')
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -136,12 +137,23 @@
|
|||
},
|
||||
methods: {
|
||||
canSubmit() {
|
||||
if (this.db_connection !== 'sqlite') {
|
||||
if (!this.db_host || !this.db_port || !this.db_user || !this.db_password || !this.db_database) {
|
||||
return false
|
||||
this.error = null
|
||||
const s = this.setup
|
||||
if (s.db_connection !== 'sqlite') {
|
||||
if (!s.db_host || !s.db_port || !s.db_user || !s.db_password || !s.db_database) {
|
||||
this.disabled = true
|
||||
return
|
||||
}
|
||||
}
|
||||
return !(!this.project || !this.description || !this.domain || !this.username || !this.password || !this.confirm_password);
|
||||
if (!s.project || !s.description || !s.domain || !s.username || !s.password || !s.confirm_password) {
|
||||
this.disabled = true
|
||||
return
|
||||
}
|
||||
if (s.password !== s.confirm_password) {
|
||||
this.disabled = true
|
||||
return
|
||||
}
|
||||
this.disabled = false
|
||||
},
|
||||
async saveSetup() {
|
||||
this.loading = true
|
||||
|
|
|
@ -82,7 +82,6 @@
|
|||
watch: {
|
||||
in_user() {
|
||||
const u = this.in_user
|
||||
delete u.password
|
||||
this.user = u
|
||||
}
|
||||
},
|
||||
|
|
|
@ -19,12 +19,6 @@
|
|||
authenticated: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
const core = await Api.core()
|
||||
if (!core.logged_in) {
|
||||
this.$router.push('/login')
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -5,30 +5,7 @@
|
|||
<img class="col-12 mt-5 mt-md-0" src="/public/banner.png">
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="login">
|
||||
<div class="form-group row">
|
||||
<label for="username" class="col-sm-2 col-form-label">Username</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" v-model="username" name="username" class="form-control" id="username" placeholder="Username" autocorrect="off" autocapitalize="none">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-sm-2 col-form-label">Password</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="password" v-model="password" name="password" class="form-control" id="password" placeholder="Password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-12">
|
||||
<button @click.prevent="login" type="submit" class="btn btn-block mb-3 btn-primary" :disabled="loading">
|
||||
{{loading ? "Loading" : "Sign in"}}
|
||||
</button>
|
||||
<div v-if="error" class="alert alert-danger" role="alert">
|
||||
Incorrect username or password
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<FormLogin/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@ -36,34 +13,20 @@
|
|||
|
||||
<script>
|
||||
import Api from "../components/API";
|
||||
import FormLogin from '../forms/Login';
|
||||
|
||||
export default {
|
||||
name: 'Login',
|
||||
components: {
|
||||
FormLogin
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
username: "",
|
||||
password: "",
|
||||
auth: {},
|
||||
loading: false,
|
||||
error: false
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async login (e) {
|
||||
this.loading = true
|
||||
this.error = false
|
||||
const auth = await Api.login(this.username, this.password)
|
||||
if (auth.error) {
|
||||
this.error = true
|
||||
} else if (auth.token) {
|
||||
this.auth = Api.saveToken(this.username, auth.token)
|
||||
await this.$store.dispatch('loadAdmin')
|
||||
this.$router.push('/dashboard')
|
||||
}
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -60,16 +60,7 @@
|
|||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade active show">
|
||||
<div class="list-group mt-3 mb-4">
|
||||
|
||||
<div v-for="(failure, index) in failures" :key="index" class="mb-2 list-group-item list-group-item-action flex-column align-items-start">
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<h5 class="mb-1">{{failure.issue}}</h5>
|
||||
<small>{{failure.created_at | moment("dddd, MMMM Do YYYY")}}</small>
|
||||
</div>
|
||||
<p class="mb-1">{{failure.issue}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<ServiceFailures :service="service"/>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" :class="{active: tab === 'incidents'}" id="incidents">
|
||||
|
@ -109,6 +100,7 @@
|
|||
<script>
|
||||
import Api from "../components/API"
|
||||
import MessageBlock from '../components/Index/MessageBlock';
|
||||
import ServiceFailures from '../components/Service/ServiceFailures';
|
||||
import Checkin from "../forms/Checkin";
|
||||
|
||||
const axisOptions = {
|
||||
|
@ -138,6 +130,7 @@
|
|||
export default {
|
||||
name: 'Service',
|
||||
components: {
|
||||
ServiceFailures,
|
||||
MessageBlock,
|
||||
Checkin
|
||||
},
|
||||
|
@ -253,7 +246,7 @@ export default {
|
|||
await this.serviceFailures()
|
||||
},
|
||||
async serviceFailures() {
|
||||
this.failures = await Api.service_failures(this.service.id, 0, 99999999999)
|
||||
this.failures = await Api.service_failures(this.service.id, this.now() - 3600, this.now(), 15)
|
||||
},
|
||||
async chartHits() {
|
||||
this.data = await Api.service_hits(this.service.id, 0, 99999999999, "hour")
|
||||
|
|
|
@ -30,23 +30,6 @@
|
|||
|
||||
<CoreSettings/>
|
||||
|
||||
<h2 class="mt-5">Bulk Import Services</h2>
|
||||
You can import multiple services based on a CSV file with the format shown on the <a href="https://github.com/hunterlong/statping/wiki/Bulk-Import-Services" target="_blank">Bulk Import Wiki</a>.
|
||||
|
||||
<div class="card mt-2">
|
||||
<div class="card-body">
|
||||
<form action="settings/bulk_import" method="POST" enctype="multipart/form-data" class="form-inline">
|
||||
<div class="form-group col-10">
|
||||
<input type="file" name="file" class="form-control-file" accept=".csv">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-outline-success right">Import</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h2 class="mt-5">Additional Settings</h2>
|
||||
<div v-if="core.domain !== ''" class="row">
|
||||
<div class="col-12">
|
||||
|
@ -57,6 +40,9 @@
|
|||
<a href="settings/export" class="btn btn-sm btn-secondary">Export Settings</a>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
Insert a domain to view QR code for the mobile app.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
|
8423
frontend/yarn.lock
8423
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -56,7 +56,10 @@ func apiRenewHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/settings", http.StatusSeeOther)
|
||||
output := apiResponse{
|
||||
Status: "success",
|
||||
}
|
||||
returnJson(output, w, r)
|
||||
}
|
||||
|
||||
func apiCoreHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -99,9 +102,8 @@ type cacheJson struct {
|
|||
}
|
||||
|
||||
func apiCacheHandler(w http.ResponseWriter, r *http.Request) {
|
||||
cache := CacheStorage
|
||||
var cacheList []cacheJson
|
||||
for k, v := range cache.List() {
|
||||
for k, v := range CacheStorage.List() {
|
||||
cacheList = append(cacheList, cacheJson{
|
||||
URL: k,
|
||||
Expiration: time.Unix(0, v.Expiration).UTC(),
|
||||
|
@ -112,8 +114,8 @@ func apiCacheHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func apiClearCacheHandler(w http.ResponseWriter, r *http.Request) {
|
||||
CacheStorage.StopRoutine()
|
||||
CacheStorage = NewStorage()
|
||||
go CleanRoutine()
|
||||
output := apiResponse{
|
||||
Status: "success",
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ func TestResetDatabase(t *testing.T) {
|
|||
err := core.TmpRecords("handlers.db")
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, core.CoreApp)
|
||||
require.NotNil(t, core.CoreApp.Config)
|
||||
}
|
||||
|
||||
func TestFailedHTTPServer(t *testing.T) {
|
||||
|
@ -43,7 +44,6 @@ func TestFailedHTTPServer(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSetupRoutes(t *testing.T) {
|
||||
|
||||
form := url.Values{}
|
||||
form.Add("db_host", "")
|
||||
form.Add("db_user", "")
|
||||
|
@ -61,17 +61,17 @@ func TestSetupRoutes(t *testing.T) {
|
|||
|
||||
tests := []HTTPTest{
|
||||
{
|
||||
Name: "Statping Setup Check",
|
||||
URL: "/setup",
|
||||
Name: "Statping Check",
|
||||
URL: "/api",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 303,
|
||||
ExpectedStatus: 200,
|
||||
},
|
||||
{
|
||||
Name: "Statping Run Setup",
|
||||
URL: "/setup",
|
||||
URL: "/api/setup",
|
||||
Method: "POST",
|
||||
Body: form.Encode(),
|
||||
ExpectedStatus: 303,
|
||||
ExpectedStatus: 200,
|
||||
HttpHeaders: []string{"Content-Type=application/x-www-form-urlencoded"},
|
||||
ExpectedFiles: []string{dir + "/config.yml", dir + "/tmp/" + types.SqliteFilename},
|
||||
}}
|
||||
|
@ -94,19 +94,19 @@ func TestMainApiRoutes(t *testing.T) {
|
|||
URL: "/api",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{`"name":"Statping Sample Data","description":"This data is only used to testing"`},
|
||||
ExpectedContains: []string{`"description":"This data is only used to testing"`},
|
||||
},
|
||||
{
|
||||
Name: "Statping Renew API Keys",
|
||||
URL: "/api/renew",
|
||||
Method: "POST",
|
||||
ExpectedStatus: 303,
|
||||
ExpectedStatus: 200,
|
||||
},
|
||||
{
|
||||
Name: "Statping Clear Cache",
|
||||
URL: "/api/clear_cache",
|
||||
Method: "POST",
|
||||
ExpectedStatus: 303,
|
||||
ExpectedStatus: 200,
|
||||
},
|
||||
{
|
||||
Name: "404 Error Page",
|
||||
|
@ -129,14 +129,14 @@ func TestApiServiceRoutes(t *testing.T) {
|
|||
Name: "Statping All Services",
|
||||
URL: "/api/services",
|
||||
Method: "GET",
|
||||
ExpectedContains: []string{`"name":"Google"`},
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{`"id":1,"name":"Google","domain":"https://google.com"`},
|
||||
},
|
||||
{
|
||||
Name: "Statping Service 1",
|
||||
URL: "/api/services/1",
|
||||
Method: "GET",
|
||||
ExpectedContains: []string{`"id":1,"name":"Google","domain":"https://google.com"`},
|
||||
ExpectedContains: []string{`"name":"Google"`},
|
||||
ExpectedStatus: 200,
|
||||
},
|
||||
{
|
||||
|
@ -370,7 +370,7 @@ func TestMessagesApiRoutes(t *testing.T) {
|
|||
URL: "/api/messages",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{`"id":1,"title":"Routine Downtime"`},
|
||||
ExpectedContains: []string{`"title":"Routine Downtime"`},
|
||||
}, {
|
||||
Name: "Statping Create Message",
|
||||
URL: "/api/messages",
|
||||
|
@ -394,7 +394,7 @@ func TestMessagesApiRoutes(t *testing.T) {
|
|||
URL: "/api/messages/1",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{`"id":1,"title":"Routine Downtime"`},
|
||||
ExpectedContains: []string{`"title":"Routine Downtime"`},
|
||||
}, {
|
||||
Name: "Statping Update Message",
|
||||
URL: "/api/messages/1",
|
||||
|
|
|
@ -1,46 +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 handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkHandleIndex(b *testing.B) {
|
||||
//b.ReportAllocs()
|
||||
//r := request(b, "/")
|
||||
//for i := 0; i < b.N; i++ {
|
||||
// rw := httptest.NewRecorder()
|
||||
// indexHandler(rw, r)
|
||||
//}
|
||||
}
|
||||
|
||||
func BenchmarkServicesHandlerIndex(b *testing.B) {
|
||||
//r := request(b, "/")
|
||||
//for i := 0; i < b.N; i++ {
|
||||
// rw := httptest.NewRecorder()
|
||||
// servicesHandler(rw, r)
|
||||
//}
|
||||
}
|
||||
|
||||
func request(t testing.TB, url string) *http.Request {
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return req
|
||||
}
|
|
@ -15,6 +15,7 @@ type Cacher interface {
|
|||
List() map[string]Item
|
||||
Lock()
|
||||
Unlock()
|
||||
StopRoutine()
|
||||
}
|
||||
|
||||
// Item is a cached reference
|
||||
|
@ -23,17 +24,23 @@ type Item struct {
|
|||
Expiration int64
|
||||
}
|
||||
|
||||
// CleanRoutine is a go routine to automatically remove expired caches that haven't been hit recently
|
||||
func CleanRoutine() {
|
||||
for CacheStorage != nil {
|
||||
CacheStorage.Lock()
|
||||
for k, v := range CacheStorage.List() {
|
||||
if v.Expired() {
|
||||
CacheStorage.Delete(k)
|
||||
// cleanRoutine is a go routine to automatically remove expired caches that haven't been hit recently
|
||||
func cleanRoutine(s *Storage) {
|
||||
duration := 5 * time.Second
|
||||
|
||||
CacheRoutine:
|
||||
for {
|
||||
select {
|
||||
case <-s.running:
|
||||
break CacheRoutine
|
||||
case <-time.After(duration):
|
||||
duration = 5 * time.Second
|
||||
for k, v := range s.List() {
|
||||
if v.Expired() {
|
||||
s.Delete(k)
|
||||
}
|
||||
}
|
||||
}
|
||||
CacheStorage.Unlock()
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,16 +54,24 @@ func (item Item) Expired() bool {
|
|||
|
||||
//Storage mecanism for caching strings in memory
|
||||
type Storage struct {
|
||||
items map[string]Item
|
||||
mu *sync.RWMutex
|
||||
items map[string]Item
|
||||
mu *sync.RWMutex
|
||||
running chan bool
|
||||
}
|
||||
|
||||
//NewStorage creates a new in memory CacheStorage
|
||||
func NewStorage() *Storage {
|
||||
return &Storage{
|
||||
items: make(map[string]Item),
|
||||
mu: &sync.RWMutex{},
|
||||
storage := &Storage{
|
||||
items: make(map[string]Item),
|
||||
mu: &sync.RWMutex{},
|
||||
running: make(chan bool),
|
||||
}
|
||||
go cleanRoutine(storage)
|
||||
return storage
|
||||
}
|
||||
|
||||
func (s Storage) StopRoutine() {
|
||||
close(s.running)
|
||||
}
|
||||
|
||||
func (s Storage) Lock() {
|
||||
|
|
|
@ -98,19 +98,19 @@ func apiThemeSaveHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
if err := source.SaveAsset([]byte(themes.Base), utils.Directory+"/assets/scss/base.scss"); err != nil {
|
||||
if err := source.SaveAsset([]byte(themes.Base), "scss/base.scss"); err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
if err := source.SaveAsset([]byte(themes.Variables), utils.Directory+"/assets/scss/variables.scss"); err != nil {
|
||||
if err := source.SaveAsset([]byte(themes.Variables), "scss/variables.scss"); err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
if err := source.SaveAsset([]byte(themes.Mobile), utils.Directory+"/assets/scss/mobile.scss"); err != nil {
|
||||
if err := source.SaveAsset([]byte(themes.Mobile), "scss/mobile.scss"); err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
if err := source.CompileSASS(utils.Directory); err != nil {
|
||||
if err := source.CompileSASS(); err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
|
@ -126,8 +126,8 @@ func apiThemeCreateHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
if err := source.CompileSASS(dir); err != nil {
|
||||
source.CopyToPublic(source.TmplBox, dir+"/assets/css", "base.css")
|
||||
if err := source.CompileSASS(); err != nil {
|
||||
source.CopyToPublic(source.TmplBox, "css", "base.css")
|
||||
log.Errorln("Default 'base.css' was inserted because SASS did not work.")
|
||||
}
|
||||
resetRouter()
|
||||
|
|
|
@ -1,146 +0,0 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/hunterlong/statping/utils"
|
||||
"github.com/stretchr/testify/require"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenericRoutes(t *testing.T) {
|
||||
|
||||
form := url.Values{}
|
||||
form.Add("username", "admin")
|
||||
form.Add("password", "password123")
|
||||
|
||||
form2 := url.Values{}
|
||||
form2.Add("username", "admin")
|
||||
form2.Add("password", "wrongpassword")
|
||||
|
||||
form3 := url.Values{}
|
||||
form3.Add("variables", "$background-color: #fcfcfc;")
|
||||
|
||||
tests := []HTTPTest{
|
||||
{
|
||||
Name: "Statping Index",
|
||||
URL: "/",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{
|
||||
`<title>Statping Sample Data Status</title>`,
|
||||
`<footer>`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Statping Incorrect Login",
|
||||
URL: "/dashboard",
|
||||
Method: "POST",
|
||||
Body: form.Encode(),
|
||||
HttpHeaders: []string{"Content-Type=application/x-www-form-urlencoded"},
|
||||
ExpectedContains: []string{"Incorrect login information submitted, try again."},
|
||||
ExpectedStatus: 200,
|
||||
},
|
||||
{
|
||||
Name: "Dashboard Routes",
|
||||
URL: "/dashboard",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{"<title>Statping | Dashboard</title>"},
|
||||
},
|
||||
{
|
||||
Name: "Services Routes",
|
||||
URL: "/services",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{"<title>Statping | Services</title>"},
|
||||
},
|
||||
{
|
||||
Name: "Users Routes",
|
||||
URL: "/users",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{"<title>Statping | Users</title>"},
|
||||
},
|
||||
{
|
||||
Name: "Messages Routes",
|
||||
URL: "/messages",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{"<title>Statping Messages</title>"},
|
||||
},
|
||||
{
|
||||
Name: "Settings Routes",
|
||||
URL: "/settings",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{"<title>Statping | Settings</title>"},
|
||||
},
|
||||
{
|
||||
Name: "Logs Routes",
|
||||
URL: "/logs",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{"<title>Statping | Logs</title>"},
|
||||
},
|
||||
{
|
||||
Name: "Help Routes",
|
||||
URL: "/help",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{"<title>Statping | Help</title>"},
|
||||
},
|
||||
{
|
||||
Name: "Logout",
|
||||
URL: "/logout",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 303,
|
||||
},
|
||||
{
|
||||
Name: "Prometheus Metrics Routes",
|
||||
URL: "/metrics",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{"statping_total_services 15"},
|
||||
},
|
||||
{
|
||||
Name: "Last Log Line",
|
||||
URL: "/logs/line",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
},
|
||||
{
|
||||
Name: "Export JSON file of all objcts",
|
||||
URL: "/settings/export",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
},
|
||||
{
|
||||
Name: "Export Static Assets",
|
||||
URL: "/settings/build",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 303,
|
||||
ExpectedFiles: []string{utils.Directory + "/assets/css/base.css"},
|
||||
},
|
||||
{
|
||||
Name: "Save SCSS",
|
||||
URL: "/settings/css",
|
||||
Method: "POST",
|
||||
Body: form3.Encode(),
|
||||
ExpectedStatus: 303,
|
||||
HttpHeaders: []string{"Content-Type=application/x-www-form-urlencoded"},
|
||||
},
|
||||
{
|
||||
Name: "Delete Assets",
|
||||
URL: "/settings/delete_assets",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 303,
|
||||
},
|
||||
}
|
||||
|
||||
for _, v := range tests {
|
||||
t.Run(v.Name, func(t *testing.T) {
|
||||
_, t, err := RunHTTPTest(v, t)
|
||||
require.Nil(t, err)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMessageRoutes(t *testing.T) {
|
||||
tests := []HTTPTest{
|
||||
{
|
||||
Name: "Messages",
|
||||
URL: "/messages",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{`<title>Statping Messages</title>`},
|
||||
},
|
||||
{
|
||||
Name: "Message 2",
|
||||
URL: "/message/2",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{`<title>Statping | Server Reboot</title>`},
|
||||
}}
|
||||
|
||||
for _, v := range tests {
|
||||
t.Run(v.Name, func(t *testing.T) {
|
||||
_, t, err := RunHTTPTest(v, t)
|
||||
require.Nil(t, err)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -30,7 +30,6 @@ var (
|
|||
log = utils.Log.WithField("type", "handlers")
|
||||
)
|
||||
|
||||
|
||||
func staticAssets(src string) http.Handler {
|
||||
return http.StripPrefix(basePath+src+"/", http.FileServer(http.Dir(utils.Directory+"/assets/"+src)))
|
||||
}
|
||||
|
@ -80,7 +79,6 @@ func Router() *mux.Router {
|
|||
}
|
||||
|
||||
api := r.NewRoute().Subrouter()
|
||||
//api := mux.NewRouter().StrictSlash(true)
|
||||
api.Use(apiMiddleware)
|
||||
|
||||
// API Routes
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServiceRoutes(t *testing.T) {
|
||||
tests := []HTTPTest{
|
||||
{
|
||||
Name: "Services",
|
||||
URL: "/services",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{`<title>Statping | Services</title>`},
|
||||
},
|
||||
{
|
||||
Name: "Services 2",
|
||||
URL: "/service/2",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{`<title>Statping Github Status</title>`},
|
||||
}, {
|
||||
Name: "chart.js index file",
|
||||
URL: "/charts.js",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
},
|
||||
}
|
||||
|
||||
for _, v := range tests {
|
||||
t.Run(v.Name, func(t *testing.T) {
|
||||
_, t, err := RunHTTPTest(v, t)
|
||||
require.Nil(t, err)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -16,240 +16,10 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/hunterlong/statping/core"
|
||||
"github.com/hunterlong/statping/core/integrations"
|
||||
"github.com/hunterlong/statping/source"
|
||||
"github.com/hunterlong/statping/types"
|
||||
"github.com/hunterlong/statping/utils"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func settingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, nil)
|
||||
}
|
||||
|
||||
func saveSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var err error
|
||||
form := parseForm(r)
|
||||
app := core.CoreApp
|
||||
name := form.Get("project")
|
||||
if name != "" {
|
||||
app.Name = name
|
||||
}
|
||||
description := form.Get("description")
|
||||
if description != app.Description {
|
||||
app.Description = description
|
||||
}
|
||||
style := form.Get("style")
|
||||
if style != app.Style {
|
||||
app.Style = style
|
||||
}
|
||||
footer := form.Get("footer")
|
||||
if footer != app.Footer.String {
|
||||
app.Footer = types.NewNullString(footer)
|
||||
}
|
||||
domain := form.Get("domain")
|
||||
if domain != app.Domain {
|
||||
app.Domain = domain
|
||||
}
|
||||
timezone := form.Get("timezone")
|
||||
timeFloat, _ := strconv.ParseFloat(timezone, 10)
|
||||
app.Timezone = float32(timeFloat)
|
||||
|
||||
app.UpdateNotify = types.NewNullBool(form.Get("update_notify") == "true")
|
||||
|
||||
app.UseCdn = types.NewNullBool(form.Get("enable_cdn") == "on")
|
||||
core.CoreApp, err = core.UpdateCore(app)
|
||||
if err != nil {
|
||||
log.Errorln(fmt.Sprintf("issue updating Core: %v", err.Error()))
|
||||
}
|
||||
|
||||
//notifiers.OnSettingsSaved(core.CoreApp.ToCore())
|
||||
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "settings")
|
||||
}
|
||||
|
||||
func saveSASSHandler(w http.ResponseWriter, r *http.Request) {
|
||||
form := parseForm(r)
|
||||
theme := form.Get("theme")
|
||||
variables := form.Get("variables")
|
||||
mobile := form.Get("mobile")
|
||||
source.SaveAsset([]byte(theme), utils.Directory+"/assets/scss/base.scss")
|
||||
source.SaveAsset([]byte(variables), utils.Directory+"/assets/scss/variables.scss")
|
||||
source.SaveAsset([]byte(mobile), utils.Directory+"/assets/scss/mobile.scss")
|
||||
source.CompileSASS(utils.Directory)
|
||||
resetRouter()
|
||||
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "settings")
|
||||
}
|
||||
|
||||
func saveAssetsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
dir := utils.Directory
|
||||
if err := source.CreateAllAssets(dir); err != nil {
|
||||
log.Errorln(err)
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
if err := source.CompileSASS(dir); err != nil {
|
||||
source.CopyToPublic(source.TmplBox, dir+"/assets/css", "base.css")
|
||||
log.Errorln("Default 'base.css' was inserted because SASS did not work.")
|
||||
}
|
||||
resetRouter()
|
||||
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "settings")
|
||||
}
|
||||
|
||||
func deleteAssetsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if err := source.DeleteAllAssets(utils.Directory); err != nil {
|
||||
log.Errorln(fmt.Errorf("error deleting all assets %v", err))
|
||||
}
|
||||
resetRouter()
|
||||
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "settings")
|
||||
}
|
||||
|
||||
func bulkImportHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var fileData bytes.Buffer
|
||||
file, _, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
log.Errorln(fmt.Errorf("error bulk import services: %v", err))
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
io.Copy(&fileData, file)
|
||||
data := fileData.String()
|
||||
|
||||
for i, line := range strings.Split(strings.TrimSuffix(data, "\n"), "\n")[1:] {
|
||||
col := strings.Split(line, ",")
|
||||
|
||||
newService, err := commaToService(col)
|
||||
if err != nil {
|
||||
log.Errorln(fmt.Errorf("issue with row %v: %v", i, err))
|
||||
continue
|
||||
}
|
||||
|
||||
service := core.ReturnService(newService)
|
||||
_, err = service.Create(true)
|
||||
if err != nil {
|
||||
log.Errorln(fmt.Errorf("cannot create service %v: %v", col[0], err))
|
||||
continue
|
||||
}
|
||||
log.Infoln(fmt.Sprintf("Created new service %v", service.Name))
|
||||
}
|
||||
|
||||
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "/settings")
|
||||
}
|
||||
|
||||
type integratorOut struct {
|
||||
Integrator *types.Integration `json:"integrator"`
|
||||
Services []*types.Service `json:"services"`
|
||||
Error error
|
||||
}
|
||||
|
||||
func integratorHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
integratorName := vars["name"]
|
||||
r.ParseForm()
|
||||
|
||||
integrator, err := integrations.Find(integratorName)
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
ExecuteResponse(w, r, "integrator.gohtml", integratorOut{
|
||||
Error: err,
|
||||
}, nil)
|
||||
return
|
||||
}
|
||||
|
||||
log.Info(r.PostForm)
|
||||
|
||||
for _, v := range integrator.Get().Fields {
|
||||
log.Info(v.Name, v.Value)
|
||||
}
|
||||
|
||||
integrations.SetFields(integrator, r.PostForm)
|
||||
|
||||
for _, v := range integrator.Get().Fields {
|
||||
log.Info(v.Name, v.Value)
|
||||
}
|
||||
|
||||
services, err := integrator.List()
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
ExecuteResponse(w, r, "integrator.gohtml", integratorOut{
|
||||
Integrator: integrator.Get(),
|
||||
Error: err,
|
||||
}, nil)
|
||||
return
|
||||
}
|
||||
|
||||
ExecuteResponse(w, r, "integrator.gohtml", integratorOut{
|
||||
Integrator: integrator.Get(),
|
||||
Services: 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) (*types.Service, error) {
|
||||
if len(s) != 17 {
|
||||
err := fmt.Errorf("does not have the expected amount of %v columns for a service", 16)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
interval, err := time.ParseDuration(s[4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
timeout, err := time.ParseDuration(s[9])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allowNotifications, err := strconv.ParseBool(s[11])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
public, err := strconv.ParseBool(s[12])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
verifySsl, err := strconv.ParseBool(s[16])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newService := &types.Service{
|
||||
Name: s[0],
|
||||
Domain: s[1],
|
||||
Expected: types.NewNullString(s[2]),
|
||||
ExpectedStatus: int(utils.ToInt(s[3])),
|
||||
Interval: int(utils.ToInt(interval.Seconds())),
|
||||
Type: s[5],
|
||||
Method: s[6],
|
||||
PostData: types.NewNullString(s[7]),
|
||||
Port: int(utils.ToInt(s[8])),
|
||||
Timeout: int(utils.ToInt(timeout.Seconds())),
|
||||
AllowNotifications: types.NewNullBool(allowNotifications),
|
||||
Public: types.NewNullBool(public),
|
||||
GroupId: int(utils.ToInt(s[13])),
|
||||
Headers: types.NewNullString(s[14]),
|
||||
Permalink: types.NewNullString(s[15]),
|
||||
VerifySSL: types.NewNullBool(verifySsl),
|
||||
}
|
||||
|
||||
return newService, nil
|
||||
|
||||
}
|
||||
|
||||
func parseForm(r *http.Request) url.Values {
|
||||
r.ParseForm()
|
||||
return r.PostForm
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUserRoutes(t *testing.T) {
|
||||
tests := []HTTPTest{
|
||||
{
|
||||
Name: "Users",
|
||||
URL: "/users",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{`<title>Statping | Users</title>`},
|
||||
},
|
||||
{
|
||||
Name: "User 2",
|
||||
URL: "/user/2",
|
||||
Method: "GET",
|
||||
ExpectedStatus: 200,
|
||||
ExpectedContains: []string{`<title>Statping | testadmin2</title>`},
|
||||
}}
|
||||
|
||||
for _, v := range tests {
|
||||
t.Run(v.Name, func(t *testing.T) {
|
||||
_, t, err := RunHTTPTest(v, t)
|
||||
require.Nil(t, err)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -80,5 +80,5 @@ func injectDatabase() {
|
|||
panic(err)
|
||||
}
|
||||
db.CreateTable(¬ifier.Notification{})
|
||||
notifier.SetDB(db, float32(-8))
|
||||
notifier.SetDB(&types.Db{db})
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import (
|
|||
"github.com/GeertJohan/go.rice"
|
||||
"github.com/hunterlong/statping/utils"
|
||||
"github.com/russross/blackfriday/v2"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
@ -46,14 +45,14 @@ func HelpMarkdown() string {
|
|||
}
|
||||
|
||||
// CompileSASS will attempt to compile the SASS files into CSS
|
||||
func CompileSASS(folder string) error {
|
||||
func CompileSASS() error {
|
||||
sassBin := os.Getenv("SASS")
|
||||
if sassBin == "" {
|
||||
sassBin = "sass"
|
||||
}
|
||||
|
||||
scssFile := fmt.Sprintf("%v/%v", folder, "assets/scss/base.scss")
|
||||
baseFile := fmt.Sprintf("%v/%v", folder, "assets/css/base.css")
|
||||
scssFile := fmt.Sprintf("%v/assets/%v", utils.Directory, "scss/base.scss")
|
||||
baseFile := fmt.Sprintf("%v/assets/%v", utils.Directory, "css/base.css")
|
||||
|
||||
log.Infoln(fmt.Sprintf("Compiling SASS %v into %v", scssFile, baseFile))
|
||||
command := fmt.Sprintf("%v %v %v", sassBin, scssFile, baseFile)
|
||||
|
@ -83,8 +82,10 @@ func UsingAssets(folder string) bool {
|
|||
} else {
|
||||
if os.Getenv("USE_ASSETS") == "true" {
|
||||
log.Infoln("Environment variable USE_ASSETS was found.")
|
||||
CreateAllAssets(folder)
|
||||
err := CompileSASS(folder)
|
||||
if err := CreateAllAssets(folder); err != nil {
|
||||
log.Warnln(err)
|
||||
}
|
||||
err := CompileSASS()
|
||||
if err != nil {
|
||||
//CopyToPublic(CssBox, folder+"/css", "base.css")
|
||||
log.Warnln("Default 'base.css' was insert because SASS did not work.")
|
||||
|
@ -97,24 +98,26 @@ func UsingAssets(folder string) bool {
|
|||
}
|
||||
|
||||
// SaveAsset will save an asset to the '/assets/' folder.
|
||||
func SaveAsset(data []byte, location string) error {
|
||||
log.Infoln(fmt.Sprintf("Saving %v", location))
|
||||
err := utils.SaveFile(location, data)
|
||||
func SaveAsset(data []byte, path string) error {
|
||||
path = fmt.Sprintf("%s/assets/%s", utils.Directory, path)
|
||||
log.Infoln(fmt.Sprintf("Saving %v", path))
|
||||
err := utils.SaveFile(path, data)
|
||||
if err != nil {
|
||||
log.Errorln(fmt.Sprintf("Failed to save %v, %v", location, err))
|
||||
log.Errorln(fmt.Sprintf("Failed to save %v, %v", path, err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// OpenAsset returns a file's contents as a string
|
||||
func OpenAsset(folder, file string) string {
|
||||
dat, err := ioutil.ReadFile(folder + "/assets/" + file)
|
||||
func OpenAsset(path string) string {
|
||||
path = fmt.Sprintf("%s/assets/%s", utils.Directory, path)
|
||||
data, err := utils.OpenFile(path)
|
||||
if err != nil {
|
||||
log.Errorln(fmt.Sprintf("Failed to open %v, %v", file, err))
|
||||
log.Errorln(fmt.Sprintf("Failed to open %v, %v", path, err))
|
||||
return ""
|
||||
}
|
||||
return string(dat)
|
||||
return data
|
||||
}
|
||||
|
||||
// CreateAllAssets will dump HTML, CSS, SCSS, and JS assets into the '/assets' directory
|
||||
|
@ -130,18 +133,19 @@ func CreateAllAssets(folder string) error {
|
|||
MakePublicFolder(fp(folder, "assets", "files"))
|
||||
log.Infoln("Inserting scss, css, and javascript files into assets folder")
|
||||
|
||||
if err := CopyAllToPublic(TmplBox, fp(folder, "assets")); err != nil {
|
||||
if err := CopyAllToPublic(TmplBox); err != nil {
|
||||
log.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
CopyToPublic(TmplBox, folder+"/assets", "robots.txt")
|
||||
CopyToPublic(TmplBox, folder+"/assets", "banner.png")
|
||||
CopyToPublic(TmplBox, folder+"/assets", "favicon.ico")
|
||||
CopyToPublic(TmplBox, folder+"/assets/files", "swagger.json")
|
||||
CopyToPublic(TmplBox, folder+"/assets/files", "postman.json")
|
||||
CopyToPublic(TmplBox, folder+"/assets/files", "grafana.json")
|
||||
CopyToPublic(TmplBox, "", "robots.txt")
|
||||
CopyToPublic(TmplBox, "", "banner.png")
|
||||
CopyToPublic(TmplBox, "", "favicon.ico")
|
||||
CopyToPublic(TmplBox, "files", "swagger.json")
|
||||
CopyToPublic(TmplBox, "files", "postman.json")
|
||||
CopyToPublic(TmplBox, "files", "grafana.json")
|
||||
log.Infoln("Compiling CSS from SCSS style...")
|
||||
err := CompileSASS(utils.Directory)
|
||||
err := CompileSASS()
|
||||
log.Infoln("Statping assets have been inserted")
|
||||
return err
|
||||
}
|
||||
|
@ -158,7 +162,7 @@ func DeleteAllAssets(folder string) error {
|
|||
}
|
||||
|
||||
// CopyAllToPublic will copy all the files in a rice box into a local folder
|
||||
func CopyAllToPublic(box *rice.Box, folder string) error {
|
||||
func CopyAllToPublic(box *rice.Box) error {
|
||||
|
||||
exclude := map[string]bool{
|
||||
"base.gohtml": true,
|
||||
|
@ -183,24 +187,26 @@ func CopyAllToPublic(box *rice.Box, folder string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filePath := filepath.Join(folder, path)
|
||||
return SaveAsset(file, filePath)
|
||||
return SaveAsset(file, path)
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// CopyToPublic will create a file from a rice Box to the '/assets' directory
|
||||
func CopyToPublic(box *rice.Box, folder, file string) error {
|
||||
assetFolder := fmt.Sprintf("%v/%v", folder, file)
|
||||
log.Infoln(fmt.Sprintf("Copying %v to %v", file, assetFolder))
|
||||
func CopyToPublic(box *rice.Box, path, file string) error {
|
||||
assetPath := fmt.Sprintf("%v/assets/%v/%v", utils.Directory, path, file)
|
||||
if path == "" {
|
||||
assetPath = fmt.Sprintf("%v/assets/%v", utils.Directory, file)
|
||||
}
|
||||
log.Infoln(fmt.Sprintf("Copying %v to %v", file, assetPath))
|
||||
base, err := box.String(file)
|
||||
if err != nil {
|
||||
log.Errorln(fmt.Sprintf("Failed to copy %v to %v, %v.", file, assetFolder, err))
|
||||
log.Errorln(fmt.Sprintf("Failed to copy %v to %v, %v.", file, assetPath, err))
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(assetFolder, []byte(base), 0744)
|
||||
err = utils.SaveFile(assetPath, []byte(base))
|
||||
if err != nil {
|
||||
log.Errorln(fmt.Sprintf("Failed to write file %v to %v, %v.", file, assetFolder, err))
|
||||
log.Errorln(fmt.Sprintf("Failed to write file %v to %v, %v.", file, assetPath, err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -18,6 +18,7 @@ package source
|
|||
import (
|
||||
"github.com/hunterlong/statping/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -42,39 +43,45 @@ func TestCreateAssets(t *testing.T) {
|
|||
assert.FileExists(t, dir+"/assets/css/base.css")
|
||||
assert.FileExists(t, dir+"/assets/scss/base.scss")
|
||||
}
|
||||
func TestCopyAllToPublic(t *testing.T) {
|
||||
err := CopyAllToPublic(TmplBox)
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestCompileSASS(t *testing.T) {
|
||||
CompileSASS(dir)
|
||||
err := CompileSASS()
|
||||
require.Nil(t, err)
|
||||
assert.True(t, UsingAssets(dir))
|
||||
}
|
||||
|
||||
func TestSaveAsset(t *testing.T) {
|
||||
data := []byte("BODY { color: black; }")
|
||||
asset := SaveAsset(data, dir, "scss/theme.scss")
|
||||
assert.Nil(t, asset)
|
||||
err := SaveAsset(data, "scss/theme.scss")
|
||||
assert.Nil(t, err)
|
||||
assert.FileExists(t, dir+"/assets/scss/theme.scss")
|
||||
}
|
||||
|
||||
func TestOpenAsset(t *testing.T) {
|
||||
asset := OpenAsset(dir, "scss/theme.scss")
|
||||
asset := OpenAsset("scss/theme.scss")
|
||||
assert.NotEmpty(t, asset)
|
||||
}
|
||||
|
||||
func TestDeleteAssets(t *testing.T) {
|
||||
assert.True(t, UsingAssets(dir))
|
||||
assert.Nil(t, DeleteAllAssets(dir))
|
||||
assert.False(t, UsingAssets(dir))
|
||||
}
|
||||
|
||||
func TestCopyToPluginFailed(t *testing.T) {
|
||||
assert.Nil(t, DeleteAllAssets(dir))
|
||||
//assert.Nil(t, DeleteAllAssets(dir))
|
||||
assert.False(t, UsingAssets(dir))
|
||||
}
|
||||
|
||||
func ExampleSaveAsset() {
|
||||
data := []byte("alert('helloooo')")
|
||||
SaveAsset(data, "js", "test.js")
|
||||
SaveAsset(data, "js/test.js")
|
||||
}
|
||||
|
||||
func ExampleOpenAsset() {
|
||||
OpenAsset("js", "main.js")
|
||||
OpenAsset("js/main.js")
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// SqliteFilename is the name of the SQLlite database file
|
||||
// SqliteFilename is the name of the SQLlite Db file
|
||||
const SqliteFilename = "statping.db"
|
||||
|
||||
// AllNotifiers contains all the Notifiers loaded
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
)
|
||||
|
||||
// Failure is a failed attempt to check a service. Any a service does not meet the expected requirements,
|
||||
// a new Failure will be inserted into database.
|
||||
// a new Failure will be inserted into Db.
|
||||
type Failure struct {
|
||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||
Issue string `gorm:"column:issue" json:"issue"`
|
||||
|
|
320
types/gorm.go
320
types/gorm.go
|
@ -116,18 +116,18 @@ type Failurer interface {
|
|||
Fails() ([]*Failure, error)
|
||||
}
|
||||
|
||||
func (it *database) Failures(id int64) Database {
|
||||
func (it *Db) Failures(id int64) Database {
|
||||
return it.Model(&Failure{}).Where("service = ?", id).Not("method = 'checkin'").Order("id desc")
|
||||
}
|
||||
|
||||
func (it *database) Fails() ([]*Failure, error) {
|
||||
func (it *Db) Fails() ([]*Failure, error) {
|
||||
var fails []*Failure
|
||||
err := it.Find(&fails)
|
||||
return fails, err.Error()
|
||||
}
|
||||
|
||||
type database struct {
|
||||
w *gorm.DB
|
||||
type Db struct {
|
||||
Database *gorm.DB
|
||||
}
|
||||
|
||||
// Openw is a drop-in replacement for Open()
|
||||
|
@ -138,316 +138,316 @@ func Openw(dialect string, args ...interface{}) (db Database, err error) {
|
|||
|
||||
// Wrap wraps gorm.DB in an interface
|
||||
func Wrap(db *gorm.DB) Database {
|
||||
return &database{db}
|
||||
return &Db{db}
|
||||
}
|
||||
|
||||
func (it *database) Close() error {
|
||||
return it.w.Close()
|
||||
func (it *Db) Close() error {
|
||||
return it.Database.Close()
|
||||
}
|
||||
|
||||
func (it *database) DB() *sql.DB {
|
||||
return it.w.DB()
|
||||
func (it *Db) DB() *sql.DB {
|
||||
return it.Database.DB()
|
||||
}
|
||||
|
||||
func (it *database) New() Database {
|
||||
return Wrap(it.w.New())
|
||||
func (it *Db) New() Database {
|
||||
return Wrap(it.Database.New())
|
||||
}
|
||||
|
||||
func (it *database) NewScope(value interface{}) *gorm.Scope {
|
||||
return it.w.NewScope(value)
|
||||
func (it *Db) NewScope(value interface{}) *gorm.Scope {
|
||||
return it.Database.NewScope(value)
|
||||
}
|
||||
|
||||
func (it *database) CommonDB() gorm.SQLCommon {
|
||||
return it.w.CommonDB()
|
||||
func (it *Db) CommonDB() gorm.SQLCommon {
|
||||
return it.Database.CommonDB()
|
||||
}
|
||||
|
||||
func (it *database) Callback() *gorm.Callback {
|
||||
return it.w.Callback()
|
||||
func (it *Db) Callback() *gorm.Callback {
|
||||
return it.Database.Callback()
|
||||
}
|
||||
|
||||
func (it *database) SetLogger(log gorm.Logger) {
|
||||
it.w.SetLogger(log)
|
||||
func (it *Db) SetLogger(log gorm.Logger) {
|
||||
it.Database.SetLogger(log)
|
||||
}
|
||||
|
||||
func (it *database) LogMode(enable bool) Database {
|
||||
return Wrap(it.w.LogMode(enable))
|
||||
func (it *Db) LogMode(enable bool) Database {
|
||||
return Wrap(it.Database.LogMode(enable))
|
||||
}
|
||||
|
||||
func (it *database) SingularTable(enable bool) {
|
||||
it.w.SingularTable(enable)
|
||||
func (it *Db) SingularTable(enable bool) {
|
||||
it.Database.SingularTable(enable)
|
||||
}
|
||||
|
||||
func (it *database) Where(query interface{}, args ...interface{}) Database {
|
||||
return Wrap(it.w.Where(query, args...))
|
||||
func (it *Db) Where(query interface{}, args ...interface{}) Database {
|
||||
return Wrap(it.Database.Where(query, args...))
|
||||
}
|
||||
|
||||
func (it *database) Or(query interface{}, args ...interface{}) Database {
|
||||
return Wrap(it.w.Or(query, args...))
|
||||
func (it *Db) Or(query interface{}, args ...interface{}) Database {
|
||||
return Wrap(it.Database.Or(query, args...))
|
||||
}
|
||||
|
||||
func (it *database) Not(query interface{}, args ...interface{}) Database {
|
||||
return Wrap(it.w.Not(query, args...))
|
||||
func (it *Db) Not(query interface{}, args ...interface{}) Database {
|
||||
return Wrap(it.Database.Not(query, args...))
|
||||
}
|
||||
|
||||
func (it *database) Limit(value int) Database {
|
||||
return Wrap(it.w.Limit(value))
|
||||
func (it *Db) Limit(value int) Database {
|
||||
return Wrap(it.Database.Limit(value))
|
||||
}
|
||||
|
||||
func (it *database) Offset(value int) Database {
|
||||
return Wrap(it.w.Offset(value))
|
||||
func (it *Db) Offset(value int) Database {
|
||||
return Wrap(it.Database.Offset(value))
|
||||
}
|
||||
|
||||
func (it *database) Order(value string, reorder ...bool) Database {
|
||||
return Wrap(it.w.Order(value, reorder...))
|
||||
func (it *Db) Order(value string, reorder ...bool) Database {
|
||||
return Wrap(it.Database.Order(value, reorder...))
|
||||
}
|
||||
|
||||
func (it *database) Select(query interface{}, args ...interface{}) Database {
|
||||
return Wrap(it.w.Select(query, args...))
|
||||
func (it *Db) Select(query interface{}, args ...interface{}) Database {
|
||||
return Wrap(it.Database.Select(query, args...))
|
||||
}
|
||||
|
||||
func (it *database) Omit(columns ...string) Database {
|
||||
return Wrap(it.w.Omit(columns...))
|
||||
func (it *Db) Omit(columns ...string) Database {
|
||||
return Wrap(it.Database.Omit(columns...))
|
||||
}
|
||||
|
||||
func (it *database) Group(query string) Database {
|
||||
return Wrap(it.w.Group(query))
|
||||
func (it *Db) Group(query string) Database {
|
||||
return Wrap(it.Database.Group(query))
|
||||
}
|
||||
|
||||
func (it *database) Having(query string, values ...interface{}) Database {
|
||||
return Wrap(it.w.Having(query, values...))
|
||||
func (it *Db) Having(query string, values ...interface{}) Database {
|
||||
return Wrap(it.Database.Having(query, values...))
|
||||
}
|
||||
|
||||
func (it *database) Joins(query string, args ...interface{}) Database {
|
||||
return Wrap(it.w.Joins(query, args...))
|
||||
func (it *Db) Joins(query string, args ...interface{}) Database {
|
||||
return Wrap(it.Database.Joins(query, args...))
|
||||
}
|
||||
|
||||
func (it *database) Scopes(funcs ...func(*gorm.DB) *gorm.DB) Database {
|
||||
return Wrap(it.w.Scopes(funcs...))
|
||||
func (it *Db) Scopes(funcs ...func(*gorm.DB) *gorm.DB) Database {
|
||||
return Wrap(it.Database.Scopes(funcs...))
|
||||
}
|
||||
|
||||
func (it *database) Unscoped() Database {
|
||||
return Wrap(it.w.Unscoped())
|
||||
func (it *Db) Unscoped() Database {
|
||||
return Wrap(it.Database.Unscoped())
|
||||
}
|
||||
|
||||
func (it *database) Attrs(attrs ...interface{}) Database {
|
||||
return Wrap(it.w.Attrs(attrs...))
|
||||
func (it *Db) Attrs(attrs ...interface{}) Database {
|
||||
return Wrap(it.Database.Attrs(attrs...))
|
||||
}
|
||||
|
||||
func (it *database) Assign(attrs ...interface{}) Database {
|
||||
return Wrap(it.w.Assign(attrs...))
|
||||
func (it *Db) Assign(attrs ...interface{}) Database {
|
||||
return Wrap(it.Database.Assign(attrs...))
|
||||
}
|
||||
|
||||
func (it *database) First(out interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.w.First(out, where...))
|
||||
func (it *Db) First(out interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.Database.First(out, where...))
|
||||
}
|
||||
|
||||
func (it *database) Last(out interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.w.Last(out, where...))
|
||||
func (it *Db) Last(out interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.Database.Last(out, where...))
|
||||
}
|
||||
|
||||
func (it *database) Find(out interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.w.Find(out, where...))
|
||||
func (it *Db) Find(out interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.Database.Find(out, where...))
|
||||
}
|
||||
|
||||
func (it *database) Scan(dest interface{}) Database {
|
||||
return Wrap(it.w.Scan(dest))
|
||||
func (it *Db) Scan(dest interface{}) Database {
|
||||
return Wrap(it.Database.Scan(dest))
|
||||
}
|
||||
|
||||
func (it *database) Row() *sql.Row {
|
||||
return it.w.Row()
|
||||
func (it *Db) Row() *sql.Row {
|
||||
return it.Database.Row()
|
||||
}
|
||||
|
||||
func (it *database) Rows() (*sql.Rows, error) {
|
||||
return it.w.Rows()
|
||||
func (it *Db) Rows() (*sql.Rows, error) {
|
||||
return it.Database.Rows()
|
||||
}
|
||||
|
||||
func (it *database) ScanRows(rows *sql.Rows, result interface{}) error {
|
||||
return it.w.ScanRows(rows, result)
|
||||
func (it *Db) ScanRows(rows *sql.Rows, result interface{}) error {
|
||||
return it.Database.ScanRows(rows, result)
|
||||
}
|
||||
|
||||
func (it *database) Pluck(column string, value interface{}) Database {
|
||||
return Wrap(it.w.Pluck(column, value))
|
||||
func (it *Db) Pluck(column string, value interface{}) Database {
|
||||
return Wrap(it.Database.Pluck(column, value))
|
||||
}
|
||||
|
||||
func (it *database) Count(value interface{}) Database {
|
||||
return Wrap(it.w.Count(value))
|
||||
func (it *Db) Count(value interface{}) Database {
|
||||
return Wrap(it.Database.Count(value))
|
||||
}
|
||||
|
||||
func (it *database) Related(value interface{}, foreignKeys ...string) Database {
|
||||
return Wrap(it.w.Related(value, foreignKeys...))
|
||||
func (it *Db) Related(value interface{}, foreignKeys ...string) Database {
|
||||
return Wrap(it.Database.Related(value, foreignKeys...))
|
||||
}
|
||||
|
||||
func (it *database) FirstOrInit(out interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.w.FirstOrInit(out, where...))
|
||||
func (it *Db) FirstOrInit(out interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.Database.FirstOrInit(out, where...))
|
||||
}
|
||||
|
||||
func (it *database) FirstOrCreate(out interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.w.FirstOrCreate(out, where...))
|
||||
func (it *Db) FirstOrCreate(out interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.Database.FirstOrCreate(out, where...))
|
||||
}
|
||||
|
||||
func (it *database) Update(attrs ...interface{}) Database {
|
||||
return Wrap(it.w.Update(attrs...))
|
||||
func (it *Db) Update(attrs ...interface{}) Database {
|
||||
return Wrap(it.Database.Update(attrs...))
|
||||
}
|
||||
|
||||
func (it *database) Updates(values interface{}, ignoreProtectedAttrs ...bool) Database {
|
||||
return Wrap(it.w.Updates(values, ignoreProtectedAttrs...))
|
||||
func (it *Db) Updates(values interface{}, ignoreProtectedAttrs ...bool) Database {
|
||||
return Wrap(it.Database.Updates(values, ignoreProtectedAttrs...))
|
||||
}
|
||||
|
||||
func (it *database) UpdateColumn(attrs ...interface{}) Database {
|
||||
return Wrap(it.w.UpdateColumn(attrs...))
|
||||
func (it *Db) UpdateColumn(attrs ...interface{}) Database {
|
||||
return Wrap(it.Database.UpdateColumn(attrs...))
|
||||
}
|
||||
|
||||
func (it *database) UpdateColumns(values interface{}) Database {
|
||||
return Wrap(it.w.UpdateColumns(values))
|
||||
func (it *Db) UpdateColumns(values interface{}) Database {
|
||||
return Wrap(it.Database.UpdateColumns(values))
|
||||
}
|
||||
|
||||
func (it *database) Save(value interface{}) Database {
|
||||
return Wrap(it.w.Save(value))
|
||||
func (it *Db) Save(value interface{}) Database {
|
||||
return Wrap(it.Database.Save(value))
|
||||
}
|
||||
|
||||
func (it *database) Create(value interface{}) Database {
|
||||
return Wrap(it.w.Create(value))
|
||||
func (it *Db) Create(value interface{}) Database {
|
||||
return Wrap(it.Database.Create(value))
|
||||
}
|
||||
|
||||
func (it *database) Delete(value interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.w.Delete(value, where...))
|
||||
func (it *Db) Delete(value interface{}, where ...interface{}) Database {
|
||||
return Wrap(it.Database.Delete(value, where...))
|
||||
}
|
||||
|
||||
func (it *database) Raw(sql string, values ...interface{}) Database {
|
||||
return Wrap(it.w.Raw(sql, values...))
|
||||
func (it *Db) Raw(sql string, values ...interface{}) Database {
|
||||
return Wrap(it.Database.Raw(sql, values...))
|
||||
}
|
||||
|
||||
func (it *database) Exec(sql string, values ...interface{}) Database {
|
||||
return Wrap(it.w.Exec(sql, values...))
|
||||
func (it *Db) Exec(sql string, values ...interface{}) Database {
|
||||
return Wrap(it.Database.Exec(sql, values...))
|
||||
}
|
||||
|
||||
func (it *database) Model(value interface{}) Database {
|
||||
return Wrap(it.w.Model(value))
|
||||
func (it *Db) Model(value interface{}) Database {
|
||||
return Wrap(it.Database.Model(value))
|
||||
}
|
||||
|
||||
func (it *database) Table(name string) Database {
|
||||
return Wrap(it.w.Table(name))
|
||||
func (it *Db) Table(name string) Database {
|
||||
return Wrap(it.Database.Table(name))
|
||||
}
|
||||
|
||||
func (it *database) Debug() Database {
|
||||
return Wrap(it.w.Debug())
|
||||
func (it *Db) Debug() Database {
|
||||
return Wrap(it.Database.Debug())
|
||||
}
|
||||
|
||||
func (it *database) Begin() Database {
|
||||
return Wrap(it.w.Begin())
|
||||
func (it *Db) Begin() Database {
|
||||
return Wrap(it.Database.Begin())
|
||||
}
|
||||
|
||||
func (it *database) Commit() Database {
|
||||
return Wrap(it.w.Commit())
|
||||
func (it *Db) Commit() Database {
|
||||
return Wrap(it.Database.Commit())
|
||||
}
|
||||
|
||||
func (it *database) Rollback() Database {
|
||||
return Wrap(it.w.Rollback())
|
||||
func (it *Db) Rollback() Database {
|
||||
return Wrap(it.Database.Rollback())
|
||||
}
|
||||
|
||||
func (it *database) NewRecord(value interface{}) bool {
|
||||
return it.w.NewRecord(value)
|
||||
func (it *Db) NewRecord(value interface{}) bool {
|
||||
return it.Database.NewRecord(value)
|
||||
}
|
||||
|
||||
func (it *database) RecordNotFound() bool {
|
||||
return it.w.RecordNotFound()
|
||||
func (it *Db) RecordNotFound() bool {
|
||||
return it.Database.RecordNotFound()
|
||||
}
|
||||
|
||||
func (it *database) CreateTable(values ...interface{}) Database {
|
||||
return Wrap(it.w.CreateTable(values...))
|
||||
func (it *Db) CreateTable(values ...interface{}) Database {
|
||||
return Wrap(it.Database.CreateTable(values...))
|
||||
}
|
||||
|
||||
func (it *database) DropTable(values ...interface{}) Database {
|
||||
return Wrap(it.w.DropTable(values...))
|
||||
func (it *Db) DropTable(values ...interface{}) Database {
|
||||
return Wrap(it.Database.DropTable(values...))
|
||||
}
|
||||
|
||||
func (it *database) DropTableIfExists(values ...interface{}) Database {
|
||||
return Wrap(it.w.DropTableIfExists(values...))
|
||||
func (it *Db) DropTableIfExists(values ...interface{}) Database {
|
||||
return Wrap(it.Database.DropTableIfExists(values...))
|
||||
}
|
||||
|
||||
func (it *database) HasTable(value interface{}) bool {
|
||||
return it.w.HasTable(value)
|
||||
func (it *Db) HasTable(value interface{}) bool {
|
||||
return it.Database.HasTable(value)
|
||||
}
|
||||
|
||||
func (it *database) AutoMigrate(values ...interface{}) Database {
|
||||
return Wrap(it.w.AutoMigrate(values...))
|
||||
func (it *Db) AutoMigrate(values ...interface{}) Database {
|
||||
return Wrap(it.Database.AutoMigrate(values...))
|
||||
}
|
||||
|
||||
func (it *database) ModifyColumn(column string, typ string) Database {
|
||||
return Wrap(it.w.ModifyColumn(column, typ))
|
||||
func (it *Db) ModifyColumn(column string, typ string) Database {
|
||||
return Wrap(it.Database.ModifyColumn(column, typ))
|
||||
}
|
||||
|
||||
func (it *database) DropColumn(column string) Database {
|
||||
return Wrap(it.w.DropColumn(column))
|
||||
func (it *Db) DropColumn(column string) Database {
|
||||
return Wrap(it.Database.DropColumn(column))
|
||||
}
|
||||
|
||||
func (it *database) AddIndex(indexName string, columns ...string) Database {
|
||||
return Wrap(it.w.AddIndex(indexName, columns...))
|
||||
func (it *Db) AddIndex(indexName string, columns ...string) Database {
|
||||
return Wrap(it.Database.AddIndex(indexName, columns...))
|
||||
}
|
||||
|
||||
func (it *database) AddUniqueIndex(indexName string, columns ...string) Database {
|
||||
return Wrap(it.w.AddUniqueIndex(indexName, columns...))
|
||||
func (it *Db) AddUniqueIndex(indexName string, columns ...string) Database {
|
||||
return Wrap(it.Database.AddUniqueIndex(indexName, columns...))
|
||||
}
|
||||
|
||||
func (it *database) RemoveIndex(indexName string) Database {
|
||||
return Wrap(it.w.RemoveIndex(indexName))
|
||||
func (it *Db) RemoveIndex(indexName string) Database {
|
||||
return Wrap(it.Database.RemoveIndex(indexName))
|
||||
}
|
||||
|
||||
func (it *database) Association(column string) *gorm.Association {
|
||||
return it.w.Association(column)
|
||||
func (it *Db) Association(column string) *gorm.Association {
|
||||
return it.Database.Association(column)
|
||||
}
|
||||
|
||||
func (it *database) Preload(column string, conditions ...interface{}) Database {
|
||||
return Wrap(it.w.Preload(column, conditions...))
|
||||
func (it *Db) Preload(column string, conditions ...interface{}) Database {
|
||||
return Wrap(it.Database.Preload(column, conditions...))
|
||||
}
|
||||
|
||||
func (it *database) Set(name string, value interface{}) Database {
|
||||
return Wrap(it.w.Set(name, value))
|
||||
func (it *Db) Set(name string, value interface{}) Database {
|
||||
return Wrap(it.Database.Set(name, value))
|
||||
}
|
||||
|
||||
func (it *database) InstantSet(name string, value interface{}) Database {
|
||||
return Wrap(it.w.InstantSet(name, value))
|
||||
func (it *Db) InstantSet(name string, value interface{}) Database {
|
||||
return Wrap(it.Database.InstantSet(name, value))
|
||||
}
|
||||
|
||||
func (it *database) Get(name string) (interface{}, bool) {
|
||||
return it.w.Get(name)
|
||||
func (it *Db) Get(name string) (interface{}, bool) {
|
||||
return it.Database.Get(name)
|
||||
}
|
||||
|
||||
func (it *database) SetJoinTableHandler(source interface{}, column string, handler gorm.JoinTableHandlerInterface) {
|
||||
it.w.SetJoinTableHandler(source, column, handler)
|
||||
func (it *Db) SetJoinTableHandler(source interface{}, column string, handler gorm.JoinTableHandlerInterface) {
|
||||
it.Database.SetJoinTableHandler(source, column, handler)
|
||||
}
|
||||
|
||||
func (it *database) AddForeignKey(field string, dest string, onDelete string, onUpdate string) Database {
|
||||
return Wrap(it.w.AddForeignKey(field, dest, onDelete, onUpdate))
|
||||
func (it *Db) AddForeignKey(field string, dest string, onDelete string, onUpdate string) Database {
|
||||
return Wrap(it.Database.AddForeignKey(field, dest, onDelete, onUpdate))
|
||||
}
|
||||
|
||||
func (it *database) AddError(err error) error {
|
||||
return it.w.AddError(err)
|
||||
func (it *Db) AddError(err error) error {
|
||||
return it.Database.AddError(err)
|
||||
}
|
||||
|
||||
func (it *database) GetErrors() (errors []error) {
|
||||
return it.w.GetErrors()
|
||||
func (it *Db) GetErrors() (errors []error) {
|
||||
return it.Database.GetErrors()
|
||||
}
|
||||
|
||||
func (it *database) RowsAffected() int64 {
|
||||
return it.w.RowsAffected
|
||||
func (it *Db) RowsAffected() int64 {
|
||||
return it.Database.RowsAffected
|
||||
}
|
||||
|
||||
func (it *database) Error() error {
|
||||
return it.w.Error
|
||||
func (it *Db) Error() error {
|
||||
return it.Database.Error
|
||||
}
|
||||
|
||||
func (it *database) Hits() ([]*Hit, error) {
|
||||
func (it *Db) Hits() ([]*Hit, error) {
|
||||
var hits []*Hit
|
||||
err := it.Find(&hits)
|
||||
return hits, err.Error()
|
||||
}
|
||||
|
||||
func (it *database) Since(ago time.Time) Database {
|
||||
func (it *Db) Since(ago time.Time) Database {
|
||||
return it.Where("created_at > ?", ago.UTC().Format(TIME))
|
||||
}
|
||||
|
||||
func (it *database) Between(t1 time.Time, t2 time.Time) Database {
|
||||
func (it *Db) Between(t1 time.Time, t2 time.Time) Database {
|
||||
return it.Where("created_at BETWEEN ? AND ?", t1.UTC().Format(TIME), t2.UTC().Format(TIME))
|
||||
}
|
||||
|
||||
|
@ -457,8 +457,8 @@ type DateScan struct {
|
|||
Value int64 `json:"y"`
|
||||
}
|
||||
|
||||
func (it *database) ToChart() ([]*DateScan, error) {
|
||||
rows, err := it.w.Rows()
|
||||
func (it *Db) ToChart() ([]*DateScan, error) {
|
||||
rows, err := it.Database.Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -481,11 +481,11 @@ func (it *database) ToChart() ([]*DateScan, error) {
|
|||
return data, err
|
||||
}
|
||||
|
||||
func (it *database) QuerySearch(r *http.Request) Database {
|
||||
func (it *Db) QuerySearch(r *http.Request) Database {
|
||||
if r == nil {
|
||||
return it
|
||||
}
|
||||
db := it.w
|
||||
db := it.Database
|
||||
start := defaultField(r, "start")
|
||||
end := defaultField(r, "end")
|
||||
limit := defaultField(r, "limit")
|
||||
|
|
|
@ -61,6 +61,16 @@ type Service struct {
|
|||
LastOnline time.Time `gorm:"-" json:"last_success"`
|
||||
Failures []FailureInterface `gorm:"-" json:"failures,omitempty" scope:"user,admin"`
|
||||
Checkins []CheckinInterface `gorm:"-" json:"checkins,omitempty" scope:"user,admin"`
|
||||
Stats Stater `gorm:"-" json:"stats,omitempty"`
|
||||
}
|
||||
|
||||
type Stater interface {
|
||||
Fetch() *Stats
|
||||
}
|
||||
|
||||
type Stats struct {
|
||||
Failures uint64 `gorm:"-" json:"failures,omitempty"`
|
||||
Hits uint64 `gorm:"-" json:"hits,omitempty"`
|
||||
}
|
||||
|
||||
// BeforeCreate for Service will set CreatedAt to UTC
|
||||
|
|
|
@ -27,7 +27,7 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
NOW = func() time.Time { return time.Now() }()
|
||||
NOW = func() time.Time { return time.Now().UTC() }()
|
||||
//HOUR_1_AGO = time.Now().Add(-1 * time.Hour)
|
||||
//HOUR_24_AGO = time.Now().Add(-24 * time.Hour)
|
||||
//HOUR_72_AGO = time.Now().Add(-72 * time.Hour)
|
||||
|
|
|
@ -36,13 +36,13 @@ func (h *Hit) BeforeCreate() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// DbConfig struct is used for the database connection and creates the 'config.yml' file
|
||||
// DbConfig struct is used for the Db connection and creates the 'config.yml' file
|
||||
type DbConfig struct {
|
||||
DbConn string `yaml:"connection" json:"connection"`
|
||||
DbHost string `yaml:"host" json:"-"`
|
||||
DbUser string `yaml:"user" json:"-"`
|
||||
DbPass string `yaml:"password" json:"-"`
|
||||
DbData string `yaml:"database" json:"-"`
|
||||
DbData string `yaml:"Db" json:"-"`
|
||||
DbPort int64 `yaml:"port" json:"-"`
|
||||
ApiKey string `yaml:"api_key" json:"-"`
|
||||
ApiSecret string `yaml:"api_secret" json:"-"`
|
||||
|
|
|
@ -33,7 +33,7 @@ type User struct {
|
|||
UserInterface `gorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
// UserInterface interfaces the database functions
|
||||
// UserInterface interfaces the Db functions
|
||||
type UserInterface interface {
|
||||
Create() (int64, error)
|
||||
Update() error
|
||||
|
|
|
@ -335,7 +335,7 @@ func DurationReadable(d time.Duration) string {
|
|||
// SaveFile will create a new file with data inside it
|
||||
// SaveFile("newfile.json", []byte('{"data": "success"}')
|
||||
func SaveFile(filename string, data []byte) error {
|
||||
err := ioutil.WriteFile(filename, data, 0655)
|
||||
err := ioutil.WriteFile(filename, data, os.ModePerm)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue