mirror of https://github.com/statping/statping
template update - checkins/failure API
parent
cdcfa2f481
commit
0a22788385
|
@ -168,7 +168,7 @@ func ExportIndexHTML() []byte {
|
||||||
}
|
}
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
r := httptest.NewRequest("GET", "/", nil)
|
r := httptest.NewRequest("GET", "/", nil)
|
||||||
handlers.ExecuteResponse(w, r, "index.html", nil, nil)
|
handlers.ExecuteResponse(w, r, "index.gohtml", nil, nil)
|
||||||
return w.Body.Bytes()
|
return w.Body.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -236,10 +236,10 @@ func recordSuccess(s *Service) {
|
||||||
notifier.OnSuccess(s.Service)
|
notifier.OnSuccess(s.Service)
|
||||||
}
|
}
|
||||||
|
|
||||||
// recordFailure will create a new 'failure' record in the database for a offline service
|
// recordFailure will create a new 'Failure' record in the database for a offline service
|
||||||
func recordFailure(s *Service, issue string) {
|
func recordFailure(s *Service, issue string) {
|
||||||
s.Online = false
|
s.Online = false
|
||||||
fail := &failure{&types.Failure{
|
fail := &Failure{&types.Failure{
|
||||||
Service: s.Id,
|
Service: s.Id,
|
||||||
Issue: issue,
|
Issue: issue,
|
||||||
PingTime: s.PingTime,
|
PingTime: s.PingTime,
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/ararog/timeago"
|
"github.com/ararog/timeago"
|
||||||
"github.com/hunterlong/statping/types"
|
"github.com/hunterlong/statping/types"
|
||||||
"github.com/hunterlong/statping/utils"
|
"github.com/hunterlong/statping/utils"
|
||||||
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,6 +32,11 @@ type CheckinHit struct {
|
||||||
*types.CheckinHit
|
*types.CheckinHit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select returns a *types.Checkin
|
||||||
|
func (c *Checkin) Select() *types.Checkin {
|
||||||
|
return c.Checkin
|
||||||
|
}
|
||||||
|
|
||||||
// Routine for checking if the last Checkin was within its interval
|
// Routine for checking if the last Checkin was within its interval
|
||||||
func (c *Checkin) Routine() {
|
func (c *Checkin) Routine() {
|
||||||
if c.Last() == nil {
|
if c.Last() == nil {
|
||||||
|
@ -42,13 +48,13 @@ CheckinLoop:
|
||||||
select {
|
select {
|
||||||
case <-c.Running:
|
case <-c.Running:
|
||||||
utils.Log(1, fmt.Sprintf("Stopping checkin routine: %v", c.Name))
|
utils.Log(1, fmt.Sprintf("Stopping checkin routine: %v", c.Name))
|
||||||
|
c.Failing = false
|
||||||
break CheckinLoop
|
break CheckinLoop
|
||||||
case <-time.After(reCheck):
|
case <-time.After(reCheck):
|
||||||
utils.Log(1, fmt.Sprintf("Checkin %v is expected at %v, checking every %v", c.Name, utils.FormatDuration(c.Expected()), utils.FormatDuration(c.Period())))
|
utils.Log(1, fmt.Sprintf("Checkin %v is expected at %v, checking every %v", c.Name, utils.FormatDuration(c.Expected()), utils.FormatDuration(c.Period())))
|
||||||
if c.Expected().Seconds() <= 0 {
|
if c.Expected().Seconds() <= 0 {
|
||||||
issue := fmt.Sprintf("Checkin %v is failing, no request since %v", c.Name, c.Last().CreatedAt)
|
issue := fmt.Sprintf("Checkin %v is failing, no request since %v", c.Name, c.Last().CreatedAt)
|
||||||
utils.Log(3, issue)
|
utils.Log(3, issue)
|
||||||
c.Service()
|
|
||||||
c.CreateFailure()
|
c.CreateFailure()
|
||||||
}
|
}
|
||||||
reCheck = c.Period()
|
reCheck = c.Period()
|
||||||
|
@ -73,23 +79,36 @@ func ReturnCheckinHit(c *types.CheckinHit) *CheckinHit {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Checkin) Service() *Service {
|
func (c *Checkin) Service() *Service {
|
||||||
service := SelectService(c.ServiceId)
|
return SelectService(c.ServiceId)
|
||||||
return service
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Checkin) CreateFailure() (int64, error) {
|
func (c *Checkin) CreateFailure() (int64, error) {
|
||||||
service := c.Service()
|
service := c.Service()
|
||||||
fail := &types.Failure{
|
c.Failing = true
|
||||||
|
fail := &Failure{&types.Failure{
|
||||||
Issue: fmt.Sprintf("Checkin %v was not reported %v ago, it expects a request every %v", c.Name, utils.FormatDuration(c.Expected()), utils.FormatDuration(c.Period())),
|
Issue: fmt.Sprintf("Checkin %v was not reported %v ago, it expects a request every %v", c.Name, utils.FormatDuration(c.Expected()), utils.FormatDuration(c.Period())),
|
||||||
Method: "checkin",
|
Method: "checkin",
|
||||||
MethodId: c.Id,
|
MethodId: c.Id,
|
||||||
Service: service.Id,
|
Service: service.Id,
|
||||||
PingTime: c.Expected().Seconds() * 0.001,
|
Checkin: c.Id,
|
||||||
}
|
PingTime: c.Expected().Seconds(),
|
||||||
|
}}
|
||||||
row := failuresDB().Create(&fail)
|
row := failuresDB().Create(&fail)
|
||||||
|
sort.Sort(types.FailSort(c.Failures))
|
||||||
|
c.Failures = append(c.Failures, fail)
|
||||||
|
if len(c.Failures) > limitedFailures {
|
||||||
|
c.Failures = c.Failures[1:]
|
||||||
|
}
|
||||||
return fail.Id, row.Error
|
return fail.Id, row.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LimitedHits will return the last amount of successful hits from a checkin
|
||||||
|
func (c *Checkin) LimitedHits(amount int64) []*types.CheckinHit {
|
||||||
|
var hits []*types.CheckinHit
|
||||||
|
checkinHitsDB().Where("checkin = ?", c.Id).Order("id desc").Limit(amount).Find(&hits)
|
||||||
|
return hits
|
||||||
|
}
|
||||||
|
|
||||||
// AllCheckins returns all checkin in system
|
// AllCheckins returns all checkin in system
|
||||||
func AllCheckins() []*Checkin {
|
func AllCheckins() []*Checkin {
|
||||||
var checkins []*Checkin
|
var checkins []*Checkin
|
||||||
|
@ -99,16 +118,14 @@ func AllCheckins() []*Checkin {
|
||||||
|
|
||||||
// SelectCheckin will find a Checkin based on the API supplied
|
// SelectCheckin will find a Checkin based on the API supplied
|
||||||
func SelectCheckin(api string) *Checkin {
|
func SelectCheckin(api string) *Checkin {
|
||||||
var checkin Checkin
|
for _, s := range Services() {
|
||||||
checkinDB().Where("api_key = ?", api).First(&checkin)
|
for _, c := range s.Select().Checkins {
|
||||||
return &checkin
|
if c.Select().ApiKey == api {
|
||||||
|
return c.(*Checkin)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// SelectCheckin will find a Checkin based on the API supplied
|
}
|
||||||
func SelectCheckinId(id int64) *Checkin {
|
return nil
|
||||||
var checkin Checkin
|
|
||||||
checkinDB().Where("id = ?", id).First(&checkin)
|
|
||||||
return &checkin
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Period will return the duration of the Checkin interval
|
// Period will return the duration of the Checkin interval
|
||||||
|
@ -150,6 +167,18 @@ func (c *Checkin) AllHits() []*types.CheckinHit {
|
||||||
return checkins
|
return checkins
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hits returns all of the CheckinHits for a given Checkin
|
||||||
|
func (c *Checkin) LimitedFailures(amount int64) []types.FailureInterface {
|
||||||
|
var failures []*Failure
|
||||||
|
var failInterfaces []types.FailureInterface
|
||||||
|
col := failuresDB().Where("checkin = ?", c.Id).Where("method = 'checkin'").Limit(amount).Order("id desc")
|
||||||
|
col.Find(&failures)
|
||||||
|
for _, f := range failures {
|
||||||
|
failInterfaces = append(failInterfaces, f)
|
||||||
|
}
|
||||||
|
return failInterfaces
|
||||||
|
}
|
||||||
|
|
||||||
// Hits returns all of the CheckinHits for a given Checkin
|
// Hits returns all of the CheckinHits for a given Checkin
|
||||||
func (c *Checkin) AllFailures() []*types.Failure {
|
func (c *Checkin) AllFailures() []*types.Failure {
|
||||||
var failures []*types.Failure
|
var failures []*types.Failure
|
||||||
|
@ -169,12 +198,14 @@ func (c *Checkin) Delete() error {
|
||||||
func (c *Checkin) Create() (int64, error) {
|
func (c *Checkin) Create() (int64, error) {
|
||||||
c.ApiKey = utils.RandomString(7)
|
c.ApiKey = utils.RandomString(7)
|
||||||
row := checkinDB().Create(&c)
|
row := checkinDB().Create(&c)
|
||||||
c.Start()
|
|
||||||
go c.Routine()
|
|
||||||
if row.Error != nil {
|
if row.Error != nil {
|
||||||
utils.Log(2, row.Error)
|
utils.Log(2, row.Error)
|
||||||
return 0, row.Error
|
return 0, row.Error
|
||||||
}
|
}
|
||||||
|
service := SelectService(c.ServiceId)
|
||||||
|
service.Checkins = append(service.Checkins, c)
|
||||||
|
c.Start()
|
||||||
|
go c.Routine()
|
||||||
return c.Id, row.Error
|
return c.Id, row.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,8 +120,8 @@ func (h *Hit) AfterFind() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterFind for failure will set the timezone
|
// AfterFind for Failure will set the timezone
|
||||||
func (f *failure) AfterFind() (err error) {
|
func (f *Failure) AfterFind() (err error) {
|
||||||
f.CreatedAt = utils.Timezoner(f.CreatedAt, CoreApp.Timezone)
|
f.CreatedAt = utils.Timezoner(f.CreatedAt, CoreApp.Timezone)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -163,8 +163,8 @@ func (h *Hit) BeforeCreate() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeforeCreate for failure will set CreatedAt to UTC
|
// BeforeCreate for Failure will set CreatedAt to UTC
|
||||||
func (f *failure) BeforeCreate() (err error) {
|
func (f *Failure) BeforeCreate() (err error) {
|
||||||
if f.CreatedAt.IsZero() {
|
if f.CreatedAt.IsZero() {
|
||||||
f.CreatedAt = time.Now().UTC()
|
f.CreatedAt = time.Now().UTC()
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type failure struct {
|
type Failure struct {
|
||||||
*types.Failure
|
*types.Failure
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,9 +33,9 @@ const (
|
||||||
limitedFailures = 32
|
limitedFailures = 32
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateFailure will create a new failure record for a service
|
// CreateFailure will create a new Failure record for a service
|
||||||
func (s *Service) CreateFailure(fail types.FailureInterface) (int64, error) {
|
func (s *Service) CreateFailure(fail types.FailureInterface) (int64, error) {
|
||||||
f := fail.(*failure)
|
f := fail.(*Failure)
|
||||||
f.Service = s.Id
|
f.Service = s.Id
|
||||||
row := failuresDB().Create(f)
|
row := failuresDB().Create(f)
|
||||||
if row.Error != nil {
|
if row.Error != nil {
|
||||||
|
@ -51,8 +51,8 @@ func (s *Service) CreateFailure(fail types.FailureInterface) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllFailures will return all failures attached to a service
|
// AllFailures will return all failures attached to a service
|
||||||
func (s *Service) AllFailures() []*failure {
|
func (s *Service) AllFailures() []*Failure {
|
||||||
var fails []*failure
|
var fails []*Failure
|
||||||
col := failuresDB().Where("service = ?", s.Id).Not("method = 'checkin'").Order("id desc")
|
col := failuresDB().Where("service = ?", s.Id).Not("method = 'checkin'").Order("id desc")
|
||||||
err := col.Find(&fails)
|
err := col.Find(&fails)
|
||||||
if err.Error != nil {
|
if err.Error != nil {
|
||||||
|
@ -72,32 +72,32 @@ func (s *Service) DeleteFailures() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LimitedFailures will return the last amount of failures from a service
|
// LimitedFailures will return the last amount of failures from a service
|
||||||
func (s *Service) LimitedFailures(amount int64) []*failure {
|
func (s *Service) LimitedFailures(amount int64) []*Failure {
|
||||||
var failArr []*failure
|
var failArr []*Failure
|
||||||
failuresDB().Where("service = ?", s.Id).Not("method = 'checkin'").Order("id desc").Limit(amount).Find(&failArr)
|
failuresDB().Where("service = ?", s.Id).Not("method = 'checkin'").Order("id desc").Limit(amount).Find(&failArr)
|
||||||
return failArr
|
return failArr
|
||||||
}
|
}
|
||||||
|
|
||||||
// LimitedFailures will return the last amount of failures from a service
|
// LimitedFailures will return the last amount of failures from a service
|
||||||
func (s *Service) LimitedCheckinFailures(amount int64) []*failure {
|
func (s *Service) LimitedCheckinFailures(amount int64) []*Failure {
|
||||||
var failArr []*failure
|
var failArr []*Failure
|
||||||
failuresDB().Where("service = ?", s.Id).Where("method = 'checkin'").Order("id desc").Limit(amount).Find(&failArr)
|
failuresDB().Where("service = ?", s.Id).Where("method = 'checkin'").Order("id desc").Limit(amount).Find(&failArr)
|
||||||
return failArr
|
return failArr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ago returns a human readable timestamp for a failure
|
// Ago returns a human readable timestamp for a Failure
|
||||||
func (f *failure) Ago() string {
|
func (f *Failure) Ago() string {
|
||||||
got, _ := timeago.TimeAgoWithTime(time.Now(), f.CreatedAt)
|
got, _ := timeago.TimeAgoWithTime(time.Now(), f.CreatedAt)
|
||||||
return got
|
return got
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select returns a *types.Failure
|
// Select returns a *types.Failure
|
||||||
func (f *failure) Select() *types.Failure {
|
func (f *Failure) Select() *types.Failure {
|
||||||
return f.Failure
|
return f.Failure
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete will remove a failure record from the database
|
// Delete will remove a Failure record from the database
|
||||||
func (f *failure) Delete() error {
|
func (f *Failure) Delete() error {
|
||||||
db := failuresDB().Delete(f)
|
db := failuresDB().Delete(f)
|
||||||
return db.Error
|
return db.Error
|
||||||
}
|
}
|
||||||
|
@ -146,8 +146,8 @@ func (s *Service) TotalFailuresSince(ago time.Time) (uint64, error) {
|
||||||
return count, err.Error
|
return count, err.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseError returns a human readable error for a failure
|
// ParseError returns a human readable error for a Failure
|
||||||
func (f *failure) ParseError() string {
|
func (f *Failure) ParseError() string {
|
||||||
if f.Method == "checkin" {
|
if f.Method == "checkin" {
|
||||||
return fmt.Sprintf("Checkin is Offline")
|
return fmt.Sprintf("Checkin is Offline")
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,13 +359,13 @@ func InsertLargeSampleData() error {
|
||||||
func insertFailureRecords(since time.Time, amount int64) {
|
func insertFailureRecords(since time.Time, amount int64) {
|
||||||
for i := int64(14); i <= 15; i++ {
|
for i := int64(14); i <= 15; i++ {
|
||||||
service := SelectService(i)
|
service := SelectService(i)
|
||||||
utils.Log(1, fmt.Sprintf("Adding %v failure records to service %v", amount, service.Name))
|
utils.Log(1, fmt.Sprintf("Adding %v Failure records to service %v", amount, service.Name))
|
||||||
createdAt := since
|
createdAt := since
|
||||||
|
|
||||||
for fi := int64(1); fi <= amount; fi++ {
|
for fi := int64(1); fi <= amount; fi++ {
|
||||||
createdAt = createdAt.Add(2 * time.Minute)
|
createdAt = createdAt.Add(2 * time.Minute)
|
||||||
|
|
||||||
failure := &failure{&types.Failure{
|
failure := &Failure{&types.Failure{
|
||||||
Service: service.Id,
|
Service: service.Id,
|
||||||
Issue: "testing right here",
|
Issue: "testing right here",
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
|
|
|
@ -55,39 +55,22 @@ func SelectService(id int64) *Service {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectServicer returns a types.ServiceInterface from in memory
|
|
||||||
func SelectServicer(id int64) types.ServiceInterface {
|
|
||||||
for _, s := range Services() {
|
|
||||||
if s.Select().Id == id {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckinProcess runs the checkin routine for each checkin attached to service
|
// CheckinProcess runs the checkin routine for each checkin attached to service
|
||||||
func (s *Service) CheckinProcess() {
|
func (s *Service) CheckinProcess() {
|
||||||
checkins := s.Checkins()
|
checkins := s.AllCheckins()
|
||||||
for _, c := range checkins {
|
for _, c := range checkins {
|
||||||
c.Start()
|
c.Start()
|
||||||
go c.Routine()
|
go c.Routine()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checkins will return a slice of Checkins for a Service
|
// AllCheckins will return a slice of AllCheckins for a Service
|
||||||
func (s *Service) Checkins() []*Checkin {
|
func (s *Service) AllCheckins() []*Checkin {
|
||||||
var checkin []*Checkin
|
var checkin []*Checkin
|
||||||
checkinDB().Where("service = ?", s.Id).Find(&checkin)
|
checkinDB().Where("service = ?", s.Id).Find(&checkin)
|
||||||
return checkin
|
return checkin
|
||||||
}
|
}
|
||||||
|
|
||||||
// LimitedCheckins will return a slice of Checkins for a Service
|
|
||||||
func (s *Service) LimitedCheckins() []*Checkin {
|
|
||||||
var checkin []*Checkin
|
|
||||||
checkinDB().Where("service = ?", s.Id).Limit(10).Find(&checkin)
|
|
||||||
return checkin
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectAllServices returns a slice of *core.Service to be store on []*core.Services, should only be called once on startup.
|
// 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) {
|
func (c *Core) SelectAllServices(start bool) ([]*Service, error) {
|
||||||
var services []*Service
|
var services []*Service
|
||||||
|
@ -106,9 +89,15 @@ func (c *Core) SelectAllServices(start bool) ([]*Service, error) {
|
||||||
for _, f := range fails {
|
for _, f := range fails {
|
||||||
service.Failures = append(service.Failures, f)
|
service.Failures = append(service.Failures, f)
|
||||||
}
|
}
|
||||||
|
checkins := service.AllCheckins()
|
||||||
|
for _, c := range checkins {
|
||||||
|
c.Failures = c.LimitedFailures(limitedFailures)
|
||||||
|
c.Hits = c.LimitedHits(limitedFailures)
|
||||||
|
service.Checkins = append(service.Checkins, c)
|
||||||
|
}
|
||||||
CoreApp.Services = append(CoreApp.Services, service)
|
CoreApp.Services = append(CoreApp.Services, service)
|
||||||
}
|
}
|
||||||
sort.Sort(ServiceOrder(CoreApp.Services))
|
reorderServices()
|
||||||
return services, db.Error
|
return services, db.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,8 +164,8 @@ type DateScanObj struct {
|
||||||
Array []DateScan `json:"data"`
|
Array []DateScan `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// lastFailure returns the last failure a service had
|
// lastFailure returns the last Failure a service had
|
||||||
func (s *Service) lastFailure() *failure {
|
func (s *Service) lastFailure() *Failure {
|
||||||
limited := s.LimitedFailures(1)
|
limited := s.LimitedFailures(1)
|
||||||
if len(limited) == 0 {
|
if len(limited) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -196,7 +185,7 @@ func (s *Service) SmallText() string {
|
||||||
if len(last) == 0 {
|
if len(last) == 0 {
|
||||||
return fmt.Sprintf("Online since %v", utils.Timezoner(s.CreatedAt, zone).Format("Monday 3:04:05PM, Jan _2 2006"))
|
return fmt.Sprintf("Online since %v", utils.Timezoner(s.CreatedAt, zone).Format("Monday 3:04:05PM, Jan _2 2006"))
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf("Online, last failure was %v", utils.Timezoner(hits[0].CreatedAt, zone).Format("Monday 3:04:05PM, Jan _2 2006"))
|
return fmt.Sprintf("Online, last Failure was %v", utils.Timezoner(hits[0].CreatedAt, zone).Format("Monday 3:04:05PM, Jan _2 2006"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(last) > 0 {
|
if len(last) > 0 {
|
||||||
|
|
|
@ -46,7 +46,7 @@ func TestCreateCheckin(t *testing.T) {
|
||||||
|
|
||||||
func TestSelectCheckin(t *testing.T) {
|
func TestSelectCheckin(t *testing.T) {
|
||||||
service := SelectService(1)
|
service := SelectService(1)
|
||||||
checkins := service.Checkins()
|
checkins := service.AllCheckins()
|
||||||
assert.NotNil(t, checkins)
|
assert.NotNil(t, checkins)
|
||||||
assert.Equal(t, 1, len(checkins))
|
assert.Equal(t, 1, len(checkins))
|
||||||
testCheckin = checkins[0]
|
testCheckin = checkins[0]
|
||||||
|
@ -63,7 +63,7 @@ func TestUpdateCheckin(t *testing.T) {
|
||||||
assert.NotZero(t, id)
|
assert.NotZero(t, id)
|
||||||
assert.NotEmpty(t, testCheckin.ApiKey)
|
assert.NotEmpty(t, testCheckin.ApiKey)
|
||||||
service := SelectService(1)
|
service := SelectService(1)
|
||||||
checkin := service.Checkins()[0]
|
checkin := service.AllCheckins()[0]
|
||||||
assert.Equal(t, int64(60), checkin.Interval)
|
assert.Equal(t, int64(60), checkin.Interval)
|
||||||
assert.Equal(t, int64(15), checkin.GracePeriod)
|
assert.Equal(t, int64(15), checkin.GracePeriod)
|
||||||
t.Log(testCheckin.Expected())
|
t.Log(testCheckin.Expected())
|
||||||
|
@ -72,7 +72,7 @@ func TestUpdateCheckin(t *testing.T) {
|
||||||
|
|
||||||
func TestCreateCheckinHits(t *testing.T) {
|
func TestCreateCheckinHits(t *testing.T) {
|
||||||
service := SelectService(1)
|
service := SelectService(1)
|
||||||
checkins := service.Checkins()
|
checkins := service.AllCheckins()
|
||||||
assert.Equal(t, 1, len(checkins))
|
assert.Equal(t, 1, len(checkins))
|
||||||
created := time.Now().UTC().Add(-60 * time.Second)
|
created := time.Now().UTC().Add(-60 * time.Second)
|
||||||
hit := ReturnCheckinHit(&types.CheckinHit{
|
hit := ReturnCheckinHit(&types.CheckinHit{
|
||||||
|
@ -88,7 +88,7 @@ func TestCreateCheckinHits(t *testing.T) {
|
||||||
func TestSelectCheckinMethods(t *testing.T) {
|
func TestSelectCheckinMethods(t *testing.T) {
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
service := SelectService(1)
|
service := SelectService(1)
|
||||||
checkins := service.Checkins()
|
checkins := service.AllCheckins()
|
||||||
assert.NotNil(t, checkins)
|
assert.NotNil(t, checkins)
|
||||||
lastHit := testCheckin.Last()
|
lastHit := testCheckin.Last()
|
||||||
assert.Equal(t, float64(60), testCheckin.Period().Seconds())
|
assert.Equal(t, float64(60), testCheckin.Period().Seconds())
|
||||||
|
|
|
@ -256,7 +256,7 @@ func TestServiceFailedTCPCheck(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateServiceFailure(t *testing.T) {
|
func TestCreateServiceFailure(t *testing.T) {
|
||||||
fail := &failure{&types.Failure{
|
fail := &Failure{&types.Failure{
|
||||||
Issue: "This is not an issue, but it would container HTTP response errors.",
|
Issue: "This is not an issue, but it would container HTTP response errors.",
|
||||||
Method: "http",
|
Method: "http",
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/hunterlong/statping/core"
|
"github.com/hunterlong/statping/core"
|
||||||
"github.com/hunterlong/statping/types"
|
"github.com/hunterlong/statping/types"
|
||||||
|
"github.com/hunterlong/statping/utils"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
@ -34,7 +35,7 @@ func apiAllCheckinsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
checkins := core.AllCheckins()
|
checkins := core.AllCheckins()
|
||||||
for _, c := range checkins {
|
for _, c := range checkins {
|
||||||
c.Hits = c.AllHits()
|
c.Hits = c.AllHits()
|
||||||
c.Failures = c.AllFailures()
|
c.Failures = c.LimitedFailures(64)
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(checkins)
|
json.NewEncoder(w).Encode(checkins)
|
||||||
|
@ -51,8 +52,8 @@ func apiCheckinHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(fmt.Errorf("checkin %v was not found", vars["api"]), w, r)
|
sendErrorJson(fmt.Errorf("checkin %v was not found", vars["api"]), w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
checkin.Hits = checkin.AllHits()
|
checkin.Hits = checkin.LimitedHits(32)
|
||||||
checkin.Failures = checkin.AllFailures()
|
checkin.Failures = checkin.LimitedFailures(32)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(checkin)
|
json.NewEncoder(w).Encode(checkin)
|
||||||
}
|
}
|
||||||
|
@ -69,6 +70,11 @@ func checkinCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
sendErrorJson(err, w, r)
|
sendErrorJson(err, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
service := core.SelectService(checkin.ServiceId)
|
||||||
|
if service == nil {
|
||||||
|
sendErrorJson(fmt.Errorf("missing service_id field"), w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
_, err = checkin.Create()
|
_, err = checkin.Create()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendErrorJson(err, w, r)
|
sendErrorJson(err, w, r)
|
||||||
|
@ -85,20 +91,25 @@ func checkinHitHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
|
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
|
||||||
checkinHit := core.ReturnCheckinHit(&types.CheckinHit{
|
|
||||||
|
hit := &types.CheckinHit{
|
||||||
Checkin: checkin.Id,
|
Checkin: checkin.Id,
|
||||||
From: ip,
|
From: ip,
|
||||||
CreatedAt: time.Now().UTC(),
|
CreatedAt: time.Now().UTC(),
|
||||||
})
|
}
|
||||||
|
checkinHit := core.ReturnCheckinHit(hit)
|
||||||
if checkin.Last() == nil {
|
if checkin.Last() == nil {
|
||||||
checkin.Start()
|
checkin.Start()
|
||||||
go checkin.Routine()
|
go checkin.Routine()
|
||||||
}
|
}
|
||||||
_, err := checkinHit.Create()
|
_, err := checkinHit.Create()
|
||||||
|
checkin.Hits = append(checkin.Hits, checkinHit.CheckinHit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendErrorJson(err, w, r)
|
sendErrorJson(err, w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
checkin.Failing = false
|
||||||
|
checkin.LastHit = utils.Timezoner(time.Now().UTC(), core.CoreApp.Timezone)
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
sendJsonAction(checkinHit, "update", w, r)
|
sendJsonAction(checkinHit, "update", w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,9 @@ import (
|
||||||
func dashboardHandler(w http.ResponseWriter, r *http.Request) {
|
func dashboardHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if !IsAuthenticated(r) {
|
if !IsAuthenticated(r) {
|
||||||
err := core.ErrorResponse{}
|
err := core.ErrorResponse{}
|
||||||
ExecuteResponse(w, r, "login.html", err, nil)
|
ExecuteResponse(w, r, "login.gohtml", err, nil)
|
||||||
} else {
|
} else {
|
||||||
ExecuteResponse(w, r, "dashboard.html", core.CoreApp, nil)
|
ExecuteResponse(w, r, "dashboard.gohtml", core.CoreApp, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
|
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
|
||||||
} else {
|
} else {
|
||||||
err := core.ErrorResponse{Error: "Incorrect login information submitted, try again."}
|
err := core.ErrorResponse{Error: "Incorrect login information submitted, try again."}
|
||||||
ExecuteResponse(w, r, "login.html", err, nil)
|
ExecuteResponse(w, r, "login.gohtml", err, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ func helpHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
help := source.HelpMarkdown()
|
help := source.HelpMarkdown()
|
||||||
ExecuteResponse(w, r, "help.html", help, nil)
|
ExecuteResponse(w, r, "help.gohtml", help, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func logsHandler(w http.ResponseWriter, r *http.Request) {
|
func logsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -84,7 +84,7 @@ func logsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
logs = append(logs, utils.LastLines[i].FormatForHtml()+"\r\n")
|
logs = append(logs, utils.LastLines[i].FormatForHtml()+"\r\n")
|
||||||
}
|
}
|
||||||
utils.LockLines.Unlock()
|
utils.LockLines.Unlock()
|
||||||
ExecuteResponse(w, r, "logs.html", logs, nil)
|
ExecuteResponse(w, r, "logs.gohtml", logs, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func logsLineHandler(w http.ResponseWriter, r *http.Request) {
|
func logsLineHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -198,7 +198,7 @@ func ExecuteResponse(w http.ResponseWriter, r *http.Request, file string, data i
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
templates := []string{"base.html", "head.html", "nav.html", "footer.html", "scripts.html", "form_service.html", "form_notifier.html", "form_user.html", "form_checkin.html", "form_message.html"}
|
templates := []string{"base.gohtml", "head.gohtml", "nav.gohtml", "footer.gohtml", "scripts.gohtml", "form_service.gohtml", "form_notifier.gohtml", "form_user.gohtml", "form_checkin.gohtml", "form_message.gohtml"}
|
||||||
|
|
||||||
javascripts := []string{"charts.js", "chart_index.js"}
|
javascripts := []string{"charts.js", "chart_index.js"}
|
||||||
|
|
||||||
|
@ -275,5 +275,5 @@ func executeJSResponse(w http.ResponseWriter, r *http.Request, file string, data
|
||||||
// error404Handler is a HTTP handler for 404 error pages
|
// error404Handler is a HTTP handler for 404 error pages
|
||||||
func error404Handler(w http.ResponseWriter, r *http.Request) {
|
func error404Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
ExecuteResponse(w, r, "error_404.html", nil, nil)
|
ExecuteResponse(w, r, "error_404.gohtml", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "/setup", http.StatusSeeOther)
|
http.Redirect(w, r, "/setup", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ExecuteResponse(w, r, "index.html", core.CoreApp, nil)
|
ExecuteResponse(w, r, "index.gohtml", core.CoreApp, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -41,7 +41,7 @@ func healthCheckHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func trayHandler(w http.ResponseWriter, r *http.Request) {
|
func trayHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
ExecuteResponse(w, r, "tray.html", core.CoreApp, nil)
|
ExecuteResponse(w, r, "tray.gohtml", core.CoreApp, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DesktopInit will run the Statping server on a specific IP and port using SQLite database
|
// DesktopInit will run the Statping server on a specific IP and port using SQLite database
|
||||||
|
|
|
@ -31,7 +31,7 @@ func messagesHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
messages, _ := core.SelectMessages()
|
messages, _ := core.SelectMessages()
|
||||||
ExecuteResponse(w, r, "messages.html", messages, nil)
|
ExecuteResponse(w, r, "messages.gohtml", messages, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func viewMessageHandler(w http.ResponseWriter, r *http.Request) {
|
func viewMessageHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -46,7 +46,7 @@ func viewMessageHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ExecuteResponse(w, r, "message.html", message, nil)
|
ExecuteResponse(w, r, "message.gohtml", message, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiAllMessagesHandler(w http.ResponseWriter, r *http.Request) {
|
func apiAllMessagesHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -104,7 +104,7 @@ func testNotificationHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
fakeNotifer, notif, err := notifier.SelectNotifier(method)
|
fakeNotifer, notif, err := notifier.SelectNotifier(method)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Log(3, fmt.Sprintf("issue saving notifier %v: %v", method, err))
|
utils.Log(3, fmt.Sprintf("issue saving notifier %v: %v", method, err))
|
||||||
ExecuteResponse(w, r, "settings.html", core.CoreApp, "/settings")
|
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "/settings")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,7 +162,7 @@ func TestApiUpdateServiceHandler(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApiDeleteServiceHandler(t *testing.T) {
|
func TestApiDeleteServiceHandler(t *testing.T) {
|
||||||
rr, err := httpRequestAPI(t, "DELETE", "/api/services/1", nil)
|
rr, err := httpRequestAPI(t, "DELETE", "/api/services/2", nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
body := rr.Body.String()
|
body := rr.Body.String()
|
||||||
var obj apiResponse
|
var obj apiResponse
|
||||||
|
@ -270,7 +270,7 @@ func TestApiRenewHandler(t *testing.T) {
|
||||||
func TestApiCheckinHandler(t *testing.T) {
|
func TestApiCheckinHandler(t *testing.T) {
|
||||||
t.SkipNow()
|
t.SkipNow()
|
||||||
service := core.SelectService(1)
|
service := core.SelectService(1)
|
||||||
checkin := service.Checkins()
|
checkin := service.AllCheckins()
|
||||||
rr, err := httpRequestAPI(t, "GET", "/api/checkin/"+checkin[0].ApiKey, nil)
|
rr, err := httpRequestAPI(t, "GET", "/api/checkin/"+checkin[0].ApiKey, nil)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
body := rr.Body.String()
|
body := rr.Body.String()
|
||||||
|
|
|
@ -51,7 +51,7 @@ func servicesHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ExecuteResponse(w, r, "services.html", core.CoreApp.Services, nil)
|
ExecuteResponse(w, r, "services.gohtml", core.CoreApp.Services, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
type serviceOrder struct {
|
type serviceOrder struct {
|
||||||
|
@ -115,7 +115,7 @@ func servicesViewHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
Data string
|
Data string
|
||||||
}{serv, start.Format(utils.FlatpickrReadable), end.Format(utils.FlatpickrReadable), start.Unix(), end.Unix(), data.ToString()}
|
}{serv, start.Format(utils.FlatpickrReadable), end.Format(utils.FlatpickrReadable), start.Unix(), end.Unix(), data.ToString()}
|
||||||
|
|
||||||
ExecuteResponse(w, r, "service.html", out, nil)
|
ExecuteResponse(w, r, "service.gohtml", out, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiServiceHandler(w http.ResponseWriter, r *http.Request) {
|
func apiServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -124,14 +124,13 @@ func apiServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
servicer := core.SelectServicer(utils.ToInt(vars["id"]))
|
servicer := core.SelectService(utils.ToInt(vars["id"]))
|
||||||
if servicer == nil {
|
if servicer == nil {
|
||||||
sendErrorJson(errors.New("service not found"), w, r)
|
sendErrorJson(errors.New("service not found"), w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
service := servicer.Select()
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(service)
|
json.NewEncoder(w).Encode(servicer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
func apiCreateServiceHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -161,8 +160,8 @@ func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
service := core.SelectServicer(utils.ToInt(vars["id"]))
|
service := core.SelectService(utils.ToInt(vars["id"]))
|
||||||
if service.Select() == nil {
|
if service == nil {
|
||||||
sendErrorJson(errors.New("service not found"), w, r)
|
sendErrorJson(errors.New("service not found"), w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -256,5 +255,5 @@ func servicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
service := core.SelectService(utils.ToInt(vars["id"]))
|
service := core.SelectService(utils.ToInt(vars["id"]))
|
||||||
service.DeleteFailures()
|
service.DeleteFailures()
|
||||||
ExecuteResponse(w, r, "services.html", core.CoreApp.Services, "/services")
|
ExecuteResponse(w, r, "services.gohtml", core.CoreApp.Services, "/services")
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ func settingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ExecuteResponse(w, r, "settings.html", core.CoreApp, nil)
|
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
func saveSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -73,7 +73,7 @@ func saveSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
utils.Log(3, fmt.Sprintf("issue updating Core: %v", err.Error()))
|
utils.Log(3, fmt.Sprintf("issue updating Core: %v", err.Error()))
|
||||||
}
|
}
|
||||||
//notifiers.OnSettingsSaved(core.CoreApp.ToCore())
|
//notifiers.OnSettingsSaved(core.CoreApp.ToCore())
|
||||||
ExecuteResponse(w, r, "settings.html", core.CoreApp, "/settings")
|
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "/settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveSASSHandler(w http.ResponseWriter, r *http.Request) {
|
func saveSASSHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -90,7 +90,7 @@ func saveSASSHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
source.SaveAsset([]byte(mobile), utils.Directory, "scss/mobile.scss")
|
source.SaveAsset([]byte(mobile), utils.Directory, "scss/mobile.scss")
|
||||||
source.CompileSASS(utils.Directory)
|
source.CompileSASS(utils.Directory)
|
||||||
resetRouter()
|
resetRouter()
|
||||||
ExecuteResponse(w, r, "settings.html", core.CoreApp, "/settings")
|
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "/settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveAssetsHandler(w http.ResponseWriter, r *http.Request) {
|
func saveAssetsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -111,7 +111,7 @@ func saveAssetsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
utils.Log(3, "Default 'base.css' was inserted because SASS did not work.")
|
utils.Log(3, "Default 'base.css' was inserted because SASS did not work.")
|
||||||
}
|
}
|
||||||
resetRouter()
|
resetRouter()
|
||||||
ExecuteResponse(w, r, "settings.html", core.CoreApp, "/settings")
|
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "/settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteAssetsHandler(w http.ResponseWriter, r *http.Request) {
|
func deleteAssetsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -121,7 +121,7 @@ func deleteAssetsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
source.DeleteAllAssets(utils.Directory)
|
source.DeleteAllAssets(utils.Directory)
|
||||||
resetRouter()
|
resetRouter()
|
||||||
ExecuteResponse(w, r, "settings.html", core.CoreApp, "/settings")
|
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "/settings")
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseId(r *http.Request) int64 {
|
func parseId(r *http.Request) int64 {
|
||||||
|
|
|
@ -34,7 +34,7 @@ func setupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
data, _ = core.LoadUsingEnv()
|
data, _ = core.LoadUsingEnv()
|
||||||
}
|
}
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
ExecuteResponse(w, r, "setup.html", data, nil)
|
ExecuteResponse(w, r, "setup.gohtml", data, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -126,5 +126,5 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupResponseError(w http.ResponseWriter, r *http.Request, a interface{}) {
|
func setupResponseError(w http.ResponseWriter, r *http.Request, a interface{}) {
|
||||||
ExecuteResponse(w, r, "setup.html", a, nil)
|
ExecuteResponse(w, r, "setup.gohtml", a, nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ func usersHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
users, _ := core.SelectAllUsers()
|
users, _ := core.SelectAllUsers()
|
||||||
ExecuteResponse(w, r, "users.html", users, nil)
|
ExecuteResponse(w, r, "users.gohtml", users, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func usersEditHandler(w http.ResponseWriter, r *http.Request) {
|
func usersEditHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -44,7 +44,7 @@ func usersEditHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
id, _ := strconv.Atoi(vars["id"])
|
id, _ := strconv.Atoi(vars["id"])
|
||||||
user, _ := core.SelectUser(int64(id))
|
user, _ := core.SelectUser(int64(id))
|
||||||
ExecuteResponse(w, r, "user.html", user, nil)
|
ExecuteResponse(w, r, "user.gohtml", user, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiUserHandler(w http.ResponseWriter, r *http.Request) {
|
func apiUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ var mobile = &mobilePush{¬ifier.Notification{
|
||||||
Method: "mobile",
|
Method: "mobile",
|
||||||
Title: "Mobile Notifications",
|
Title: "Mobile Notifications",
|
||||||
Description: `Receive push notifications on your Android or iPhone devices using the Statping App. You can scan the Authentication QR Code found in Settings to get the mobile app setup in seconds.
|
Description: `Receive push notifications on your Android or iPhone devices using the Statping App. You can scan the Authentication QR Code found in Settings to get the mobile app setup in seconds.
|
||||||
<p align="center"><a href="https://play.google.com/store/apps/details?id=com.statup"><img src="https://img.cjx.io/google-play.svg"></a> <a href="https://testflight.apple.com/join/TuBIj25Q"><img src="https://img.cjx.io/app-store-badge.svg"></a></p>`,
|
<p align="center"><a href="https://play.google.com/store/apps/details?id=com.statping"><img src="https://img.cjx.io/google-play.svg"></a> <a href="https://testflight.apple.com/join/TuBIj25Q"><img src="https://img.cjx.io/app-store-badge.svg"></a></p>`,
|
||||||
Author: "Hunter Long",
|
Author: "Hunter Long",
|
||||||
AuthorUrl: "https://github.com/hunterlong",
|
AuthorUrl: "https://github.com/hunterlong",
|
||||||
Delay: time.Duration(5 * time.Second),
|
Delay: time.Duration(5 * time.Second),
|
||||||
|
|
|
@ -104,7 +104,7 @@ func TestSlackNotifier(t *testing.T) {
|
||||||
slacker.OnSuccess(TestService)
|
slacker.OnSuccess(TestService)
|
||||||
assert.Equal(t, 1, len(slacker.Queue))
|
assert.Equal(t, 1, len(slacker.Queue))
|
||||||
go notifier.Queue(slacker)
|
go notifier.Queue(slacker)
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(6 * time.Second)
|
||||||
assert.Equal(t, 0, len(slacker.Queue))
|
assert.Equal(t, 0, len(slacker.Queue))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -135,11 +135,11 @@ func CreateAllAssets(folder string) error {
|
||||||
MakePublicFolder(folder + "/assets/font")
|
MakePublicFolder(folder + "/assets/font")
|
||||||
MakePublicFolder(folder + "/assets/files")
|
MakePublicFolder(folder + "/assets/files")
|
||||||
utils.Log(1, "Inserting scss, css, and javascript files into assets folder")
|
utils.Log(1, "Inserting scss, css, and javascript files into assets folder")
|
||||||
CopyAllToPublic(ScssBox, "scss")
|
CopyAllToPublic(ScssBox, "scss/")
|
||||||
CopyAllToPublic(FontBox, "font")
|
CopyAllToPublic(FontBox, "font/")
|
||||||
CopyAllToPublic(CssBox, "css")
|
CopyAllToPublic(CssBox, "css/")
|
||||||
CopyAllToPublic(JsBox, "js")
|
CopyAllToPublic(JsBox, "js/")
|
||||||
CopyToPublic(FontBox, folder+"/assets/font", "all.css")
|
CopyToPublic(FontBox, folder+"/assets/font/", "all.css")
|
||||||
CopyToPublic(TmplBox, folder+"/assets", "robots.txt")
|
CopyToPublic(TmplBox, folder+"/assets", "robots.txt")
|
||||||
CopyToPublic(TmplBox, folder+"/assets", "banner.png")
|
CopyToPublic(TmplBox, folder+"/assets", "banner.png")
|
||||||
CopyToPublic(TmplBox, folder+"/assets", "favicon.ico")
|
CopyToPublic(TmplBox, folder+"/assets", "favicon.ico")
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"info": {
|
"info": {
|
||||||
"_postman_id": "d74ac4a3-8915-46e8-8ed2-5044ea4ce53b",
|
"_postman_id": "d74ac4a3-8915-46e8-8ed2-5044ea4ce53b",
|
||||||
"name": "Statping",
|
"name": "Statup",
|
||||||
"description": "Statping API Requests",
|
"description": "Statup API Requests",
|
||||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||||
},
|
},
|
||||||
"item": [
|
"item": [
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
"name": "Main",
|
"name": "Main",
|
||||||
"item": [
|
"item": [
|
||||||
{
|
{
|
||||||
"name": "Statping Details",
|
"name": "Statup Details",
|
||||||
"event": [
|
"event": [
|
||||||
{
|
{
|
||||||
"listen": "test",
|
"listen": "test",
|
||||||
|
@ -164,7 +164,7 @@
|
||||||
],
|
],
|
||||||
"body": {
|
"body": {
|
||||||
"mode": "raw",
|
"mode": "raw",
|
||||||
"raw": "{\n\t\"token\": {\n\t\t\"value\": \"ExponentPushToken[SBryVgIxjgaMKCP5MBtt2J]\"\n\t},\n\t\"user\": {\n\t\t\"username\": \"Brent\"\n\t}\n}"
|
"raw": ""
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "{{endpoint}}/api/services/1",
|
"raw": "{{endpoint}}/api/services/1",
|
||||||
|
@ -250,7 +250,7 @@
|
||||||
"pm.test(\"Create Service\", function () {",
|
"pm.test(\"Create Service\", function () {",
|
||||||
" var jsonData = pm.response.json();",
|
" var jsonData = pm.response.json();",
|
||||||
" pm.expect(jsonData.output.name).to.eql(\"New Service\");",
|
" pm.expect(jsonData.output.name).to.eql(\"New Service\");",
|
||||||
" pm.expect(jsonData.output.domain).to.eql(\"https://statping.com\");",
|
" pm.expect(jsonData.output.domain).to.eql(\"https://statup.io\");",
|
||||||
" pm.expect(jsonData.output.type).to.eql(\"http\");",
|
" pm.expect(jsonData.output.type).to.eql(\"http\");",
|
||||||
" pm.expect(jsonData.output.method).to.eql(\"GET\");",
|
" pm.expect(jsonData.output.method).to.eql(\"GET\");",
|
||||||
" pm.expect(jsonData.output.expected_status).to.eql(200);",
|
" pm.expect(jsonData.output.expected_status).to.eql(200);",
|
||||||
|
@ -280,7 +280,7 @@
|
||||||
],
|
],
|
||||||
"body": {
|
"body": {
|
||||||
"mode": "raw",
|
"mode": "raw",
|
||||||
"raw": "{\n \"name\": \"New Service\",\n \"domain\": \"https://statping.com\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 30,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 30,\n \"order_id\": 0\n}"
|
"raw": "{\n \"name\": \"New Service\",\n \"domain\": \"https://statup.io\",\n \"expected\": \"\",\n \"expected_status\": 200,\n \"check_interval\": 30,\n \"type\": \"http\",\n \"method\": \"GET\",\n \"post_data\": \"\",\n \"port\": 0,\n \"timeout\": 30,\n \"order_id\": 0\n}"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "{{endpoint}}/api/services",
|
"raw": "{{endpoint}}/api/services",
|
||||||
|
@ -439,14 +439,14 @@
|
||||||
"header": [],
|
"header": [],
|
||||||
"body": {},
|
"body": {},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "{{endpoint}}/api/services/1",
|
"raw": "{{endpoint}}/api/services/2",
|
||||||
"host": [
|
"host": [
|
||||||
"{{endpoint}}"
|
"{{endpoint}}"
|
||||||
],
|
],
|
||||||
"path": [
|
"path": [
|
||||||
"api",
|
"api",
|
||||||
"services",
|
"services",
|
||||||
"1"
|
"2"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -75,15 +75,15 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if Auth}}
|
{{if Auth}}
|
||||||
|
{{$failures := $s.LimitedFailures 16}}
|
||||||
<nav class="nav nav-pills flex-column flex-sm-row mt-3" id="service_tabs" role="serviceLists">
|
<nav class="nav nav-pills flex-column flex-sm-row mt-3" id="service_tabs" role="serviceLists">
|
||||||
<a class="flex-sm-fill text-sm-center nav-link active" id="edit-tab" data-toggle="tab" href="#edit" role="tab" aria-controls="edit" aria-selected="false">Edit Service</a>
|
<a class="flex-sm-fill text-sm-center nav-link active" id="edit-tab" data-toggle="tab" href="#edit" role="tab" aria-controls="edit" aria-selected="false">Edit Service</a>
|
||||||
<a class="flex-sm-fill text-sm-center nav-link" id="failures-tab" data-toggle="tab" href="#failures" role="tab" aria-controls="failures" aria-selected="true">Failures</a>
|
<a class="flex-sm-fill text-sm-center nav-link{{ if not $failures }}disabled{{end}}" id="failures-tab" data-toggle="tab" href="#failures" role="tab" aria-controls="failures" aria-selected="true">Failures</a>
|
||||||
<a class="flex-sm-fill text-sm-center nav-link" id="checkins-tab" data-toggle="tab" href="#checkins" role="tab" aria-controls="checkins" aria-selected="false">Checkins</a>
|
<a class="flex-sm-fill text-sm-center nav-link" id="checkins-tab" data-toggle="tab" href="#checkins" role="tab" aria-controls="checkins" aria-selected="false">Checkins</a>
|
||||||
<a class="flex-sm-fill text-sm-center nav-link" id="response-tab" data-toggle="tab" href="#response" role="tab" aria-controls="response" aria-selected="false">Response</a>
|
<a class="flex-sm-fill text-sm-center nav-link" id="response-tab" data-toggle="tab" href="#response" role="tab" aria-controls="response" aria-selected="false">Response</a>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="tab-content" id="myTabContent">
|
<div class="tab-content" id="myTabContent">
|
||||||
<div class="tab-pane fade" id="failures" role="serviceLists" aria-labelledby="failures-tab">
|
<div class="tab-pane fade" id="failures" role="serviceLists" aria-labelledby="failures-tab">
|
||||||
{{$failures := $s.LimitedFailures 16}}
|
|
||||||
{{ if $failures }}
|
{{ if $failures }}
|
||||||
<div class="list-group mt-3 mb-4">
|
<div class="list-group mt-3 mb-4">
|
||||||
{{ range $failures }}
|
{{ range $failures }}
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane fade" id="checkins" role="serviceLists" aria-labelledby="checkins-tab">
|
<div class="tab-pane fade" id="checkins" role="serviceLists" aria-labelledby="checkins-tab">
|
||||||
{{if $s.LimitedCheckins}}
|
{{if $s.AllCheckins}}
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -111,7 +111,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody style="font-size: 10pt;">
|
<tbody style="font-size: 10pt;">
|
||||||
{{range $s.LimitedCheckins}}
|
{{range $s.AllCheckins}}
|
||||||
{{ $ch := . }}
|
{{ $ch := . }}
|
||||||
<tr id="checkin_{{$ch.Id}}" class="{{ if lt $ch.Expected 0}}bg-warning text-black{{else}}bg-light{{end}}">
|
<tr id="checkin_{{$ch.Id}}" class="{{ if lt $ch.Expected 0}}bg-warning text-black{{else}}bg-light{{end}}">
|
||||||
<td>{{$ch.Name}}<br><a href="{{$ch.Link}}" target="_blank">{{$ch.Link}}</a></td>
|
<td>{{$ch.Name}}<br><a href="{{$ch.Link}}" target="_blank">{{$ch.Link}}</a></td>
|
|
@ -30,14 +30,20 @@ type Checkin struct {
|
||||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||||
Running chan bool `gorm:"-" json:"-"`
|
Running chan bool `gorm:"-" json:"-"`
|
||||||
|
Failing bool `gorm:"-" json:"failing"`
|
||||||
|
LastHit time.Time `gorm:"-" json:"last_hit"`
|
||||||
Hits []*CheckinHit `gorm:"-" json:"hits"`
|
Hits []*CheckinHit `gorm:"-" json:"hits"`
|
||||||
Failures []*Failure `gorm:"-" json:"failures"`
|
Failures []FailureInterface `gorm:"-" json:"failures"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CheckinInterface interface {
|
||||||
|
Select() *Checkin
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckinHit is a successful response from a Checkin
|
// CheckinHit is a successful response from a Checkin
|
||||||
type CheckinHit struct {
|
type CheckinHit struct {
|
||||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||||
Checkin int64 `gorm:"index;column:checkin" json:"checkin"`
|
Checkin int64 `gorm:"index;column:checkin" json:"-"`
|
||||||
From string `gorm:"column:from_location" json:"from"`
|
From string `gorm:"column:from_location" json:"from"`
|
||||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ type Failure struct {
|
||||||
Method string `gorm:"column:method" json:"method,omitempty"`
|
Method string `gorm:"column:method" json:"method,omitempty"`
|
||||||
MethodId int64 `gorm:"column:method_id" json:"method_id,omitempty"`
|
MethodId int64 `gorm:"column:method_id" json:"method_id,omitempty"`
|
||||||
Service int64 `gorm:"index;column:service" json:"-"`
|
Service int64 `gorm:"index;column:service" json:"-"`
|
||||||
|
Checkin int64 `gorm:"index;column:checkin" json:"-"`
|
||||||
PingTime float64 `gorm:"column:ping_time" json:"ping"`
|
PingTime float64 `gorm:"column:ping_time" json:"ping"`
|
||||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,9 @@ type Service struct {
|
||||||
SleepDuration time.Duration `gorm:"-" json:"-"`
|
SleepDuration time.Duration `gorm:"-" json:"-"`
|
||||||
LastResponse string `gorm:"-" json:"-"`
|
LastResponse string `gorm:"-" json:"-"`
|
||||||
LastStatusCode int `gorm:"-" json:"status_code"`
|
LastStatusCode int `gorm:"-" json:"status_code"`
|
||||||
LastOnline time.Time `gorm:"-" json:"last_online"`
|
LastOnline time.Time `gorm:"-" json:"last_success"`
|
||||||
Failures []FailureInterface `gorm:"-" json:"failures,omitempty"`
|
Failures []FailureInterface `gorm:"-" json:"failures,omitempty"`
|
||||||
|
Checkins []CheckinInterface `gorm:"-" json:"checkins,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceInterface interface {
|
type ServiceInterface interface {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
0.79.97
|
0.79.98
|
Loading…
Reference in New Issue