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()
|
||||
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()
|
||||
}
|
||||
|
||||
|
|
|
@ -236,10 +236,10 @@ func recordSuccess(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) {
|
||||
s.Online = false
|
||||
fail := &failure{&types.Failure{
|
||||
fail := &Failure{&types.Failure{
|
||||
Service: s.Id,
|
||||
Issue: issue,
|
||||
PingTime: s.PingTime,
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/ararog/timeago"
|
||||
"github.com/hunterlong/statping/types"
|
||||
"github.com/hunterlong/statping/utils"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -31,6 +32,11 @@ type CheckinHit struct {
|
|||
*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
|
||||
func (c *Checkin) Routine() {
|
||||
if c.Last() == nil {
|
||||
|
@ -42,13 +48,13 @@ CheckinLoop:
|
|||
select {
|
||||
case <-c.Running:
|
||||
utils.Log(1, fmt.Sprintf("Stopping checkin routine: %v", c.Name))
|
||||
c.Failing = false
|
||||
break CheckinLoop
|
||||
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())))
|
||||
if c.Expected().Seconds() <= 0 {
|
||||
issue := fmt.Sprintf("Checkin %v is failing, no request since %v", c.Name, c.Last().CreatedAt)
|
||||
utils.Log(3, issue)
|
||||
c.Service()
|
||||
c.CreateFailure()
|
||||
}
|
||||
reCheck = c.Period()
|
||||
|
@ -73,23 +79,36 @@ func ReturnCheckinHit(c *types.CheckinHit) *CheckinHit {
|
|||
}
|
||||
|
||||
func (c *Checkin) Service() *Service {
|
||||
service := SelectService(c.ServiceId)
|
||||
return service
|
||||
return SelectService(c.ServiceId)
|
||||
}
|
||||
|
||||
func (c *Checkin) CreateFailure() (int64, error) {
|
||||
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())),
|
||||
Method: "checkin",
|
||||
MethodId: c.Id,
|
||||
Service: service.Id,
|
||||
PingTime: c.Expected().Seconds() * 0.001,
|
||||
}
|
||||
Checkin: c.Id,
|
||||
PingTime: c.Expected().Seconds(),
|
||||
}}
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
func AllCheckins() []*Checkin {
|
||||
var checkins []*Checkin
|
||||
|
@ -99,16 +118,14 @@ func AllCheckins() []*Checkin {
|
|||
|
||||
// SelectCheckin will find a Checkin based on the API supplied
|
||||
func SelectCheckin(api string) *Checkin {
|
||||
var checkin Checkin
|
||||
checkinDB().Where("api_key = ?", api).First(&checkin)
|
||||
return &checkin
|
||||
}
|
||||
|
||||
// SelectCheckin will find a Checkin based on the API supplied
|
||||
func SelectCheckinId(id int64) *Checkin {
|
||||
var checkin Checkin
|
||||
checkinDB().Where("id = ?", id).First(&checkin)
|
||||
return &checkin
|
||||
for _, s := range Services() {
|
||||
for _, c := range s.Select().Checkins {
|
||||
if c.Select().ApiKey == api {
|
||||
return c.(*Checkin)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Period will return the duration of the Checkin interval
|
||||
|
@ -150,6 +167,18 @@ func (c *Checkin) AllHits() []*types.CheckinHit {
|
|||
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
|
||||
func (c *Checkin) AllFailures() []*types.Failure {
|
||||
var failures []*types.Failure
|
||||
|
@ -169,12 +198,14 @@ func (c *Checkin) Delete() error {
|
|||
func (c *Checkin) Create() (int64, error) {
|
||||
c.ApiKey = utils.RandomString(7)
|
||||
row := checkinDB().Create(&c)
|
||||
c.Start()
|
||||
go c.Routine()
|
||||
if row.Error != nil {
|
||||
utils.Log(2, 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
|
||||
}
|
||||
|
||||
|
|
|
@ -120,8 +120,8 @@ func (h *Hit) AfterFind() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// AfterFind for failure will set the timezone
|
||||
func (f *failure) AfterFind() (err error) {
|
||||
// AfterFind for Failure will set the timezone
|
||||
func (f *Failure) AfterFind() (err error) {
|
||||
f.CreatedAt = utils.Timezoner(f.CreatedAt, CoreApp.Timezone)
|
||||
return
|
||||
}
|
||||
|
@ -163,8 +163,8 @@ func (h *Hit) BeforeCreate() (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// BeforeCreate for failure will set CreatedAt to UTC
|
||||
func (f *failure) BeforeCreate() (err error) {
|
||||
// BeforeCreate for Failure will set CreatedAt to UTC
|
||||
func (f *Failure) BeforeCreate() (err error) {
|
||||
if f.CreatedAt.IsZero() {
|
||||
f.CreatedAt = time.Now().UTC()
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
type failure struct {
|
||||
type Failure struct {
|
||||
*types.Failure
|
||||
}
|
||||
|
||||
|
@ -33,9 +33,9 @@ const (
|
|||
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) {
|
||||
f := fail.(*failure)
|
||||
f := fail.(*Failure)
|
||||
f.Service = s.Id
|
||||
row := failuresDB().Create(f)
|
||||
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
|
||||
func (s *Service) AllFailures() []*failure {
|
||||
var fails []*failure
|
||||
func (s *Service) AllFailures() []*Failure {
|
||||
var fails []*Failure
|
||||
col := failuresDB().Where("service = ?", s.Id).Not("method = 'checkin'").Order("id desc")
|
||||
err := col.Find(&fails)
|
||||
if err.Error != nil {
|
||||
|
@ -72,32 +72,32 @@ func (s *Service) DeleteFailures() {
|
|||
}
|
||||
|
||||
// LimitedFailures will return the last amount of failures from a service
|
||||
func (s *Service) LimitedFailures(amount int64) []*failure {
|
||||
var failArr []*failure
|
||||
func (s *Service) LimitedFailures(amount int64) []*Failure {
|
||||
var failArr []*Failure
|
||||
failuresDB().Where("service = ?", s.Id).Not("method = 'checkin'").Order("id desc").Limit(amount).Find(&failArr)
|
||||
return failArr
|
||||
}
|
||||
|
||||
// LimitedFailures will return the last amount of failures from a service
|
||||
func (s *Service) LimitedCheckinFailures(amount int64) []*failure {
|
||||
var failArr []*failure
|
||||
func (s *Service) LimitedCheckinFailures(amount int64) []*Failure {
|
||||
var failArr []*Failure
|
||||
failuresDB().Where("service = ?", s.Id).Where("method = 'checkin'").Order("id desc").Limit(amount).Find(&failArr)
|
||||
return failArr
|
||||
}
|
||||
|
||||
// Ago returns a human readable timestamp for a failure
|
||||
func (f *failure) Ago() string {
|
||||
// Ago returns a human readable timestamp for a Failure
|
||||
func (f *Failure) Ago() string {
|
||||
got, _ := timeago.TimeAgoWithTime(time.Now(), f.CreatedAt)
|
||||
return got
|
||||
}
|
||||
|
||||
// Select returns a *types.Failure
|
||||
func (f *failure) Select() *types.Failure {
|
||||
func (f *Failure) Select() *types.Failure {
|
||||
return f.Failure
|
||||
}
|
||||
|
||||
// Delete will remove a failure record from the database
|
||||
func (f *failure) Delete() error {
|
||||
// Delete will remove a Failure record from the database
|
||||
func (f *Failure) Delete() error {
|
||||
db := failuresDB().Delete(f)
|
||||
return db.Error
|
||||
}
|
||||
|
@ -146,8 +146,8 @@ func (s *Service) TotalFailuresSince(ago time.Time) (uint64, error) {
|
|||
return count, err.Error
|
||||
}
|
||||
|
||||
// ParseError returns a human readable error for a failure
|
||||
func (f *failure) ParseError() string {
|
||||
// ParseError returns a human readable error for a Failure
|
||||
func (f *Failure) ParseError() string {
|
||||
if f.Method == "checkin" {
|
||||
return fmt.Sprintf("Checkin is Offline")
|
||||
}
|
||||
|
|
|
@ -359,13 +359,13 @@ func InsertLargeSampleData() error {
|
|||
func insertFailureRecords(since time.Time, amount int64) {
|
||||
for i := int64(14); i <= 15; 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
|
||||
|
||||
for fi := int64(1); fi <= amount; fi++ {
|
||||
createdAt = createdAt.Add(2 * time.Minute)
|
||||
|
||||
failure := &failure{&types.Failure{
|
||||
failure := &Failure{&types.Failure{
|
||||
Service: service.Id,
|
||||
Issue: "testing right here",
|
||||
CreatedAt: createdAt,
|
||||
|
|
|
@ -55,39 +55,22 @@ func SelectService(id int64) *Service {
|
|||
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
|
||||
func (s *Service) CheckinProcess() {
|
||||
checkins := s.Checkins()
|
||||
checkins := s.AllCheckins()
|
||||
for _, c := range checkins {
|
||||
c.Start()
|
||||
go c.Routine()
|
||||
}
|
||||
}
|
||||
|
||||
// Checkins will return a slice of Checkins for a Service
|
||||
func (s *Service) Checkins() []*Checkin {
|
||||
// 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)
|
||||
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.
|
||||
func (c *Core) SelectAllServices(start bool) ([]*Service, error) {
|
||||
var services []*Service
|
||||
|
@ -106,9 +89,15 @@ func (c *Core) SelectAllServices(start bool) ([]*Service, error) {
|
|||
for _, f := range fails {
|
||||
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)
|
||||
}
|
||||
sort.Sort(ServiceOrder(CoreApp.Services))
|
||||
reorderServices()
|
||||
return services, db.Error
|
||||
}
|
||||
|
||||
|
@ -175,8 +164,8 @@ type DateScanObj struct {
|
|||
Array []DateScan `json:"data"`
|
||||
}
|
||||
|
||||
// lastFailure returns the last failure a service had
|
||||
func (s *Service) lastFailure() *failure {
|
||||
// lastFailure returns the last Failure a service had
|
||||
func (s *Service) lastFailure() *Failure {
|
||||
limited := s.LimitedFailures(1)
|
||||
if len(limited) == 0 {
|
||||
return nil
|
||||
|
@ -196,7 +185,7 @@ func (s *Service) SmallText() string {
|
|||
if len(last) == 0 {
|
||||
return fmt.Sprintf("Online since %v", utils.Timezoner(s.CreatedAt, zone).Format("Monday 3:04:05PM, Jan _2 2006"))
|
||||
} 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 {
|
||||
|
|
|
@ -46,7 +46,7 @@ func TestCreateCheckin(t *testing.T) {
|
|||
|
||||
func TestSelectCheckin(t *testing.T) {
|
||||
service := SelectService(1)
|
||||
checkins := service.Checkins()
|
||||
checkins := service.AllCheckins()
|
||||
assert.NotNil(t, checkins)
|
||||
assert.Equal(t, 1, len(checkins))
|
||||
testCheckin = checkins[0]
|
||||
|
@ -63,7 +63,7 @@ func TestUpdateCheckin(t *testing.T) {
|
|||
assert.NotZero(t, id)
|
||||
assert.NotEmpty(t, testCheckin.ApiKey)
|
||||
service := SelectService(1)
|
||||
checkin := service.Checkins()[0]
|
||||
checkin := service.AllCheckins()[0]
|
||||
assert.Equal(t, int64(60), checkin.Interval)
|
||||
assert.Equal(t, int64(15), checkin.GracePeriod)
|
||||
t.Log(testCheckin.Expected())
|
||||
|
@ -72,7 +72,7 @@ func TestUpdateCheckin(t *testing.T) {
|
|||
|
||||
func TestCreateCheckinHits(t *testing.T) {
|
||||
service := SelectService(1)
|
||||
checkins := service.Checkins()
|
||||
checkins := service.AllCheckins()
|
||||
assert.Equal(t, 1, len(checkins))
|
||||
created := time.Now().UTC().Add(-60 * time.Second)
|
||||
hit := ReturnCheckinHit(&types.CheckinHit{
|
||||
|
@ -88,7 +88,7 @@ func TestCreateCheckinHits(t *testing.T) {
|
|||
func TestSelectCheckinMethods(t *testing.T) {
|
||||
time.Sleep(5 * time.Second)
|
||||
service := SelectService(1)
|
||||
checkins := service.Checkins()
|
||||
checkins := service.AllCheckins()
|
||||
assert.NotNil(t, checkins)
|
||||
lastHit := testCheckin.Last()
|
||||
assert.Equal(t, float64(60), testCheckin.Period().Seconds())
|
||||
|
|
|
@ -256,7 +256,7 @@ func TestServiceFailedTCPCheck(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.",
|
||||
Method: "http",
|
||||
}}
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
"github.com/hunterlong/statping/core"
|
||||
"github.com/hunterlong/statping/types"
|
||||
"github.com/hunterlong/statping/utils"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
@ -34,7 +35,7 @@ func apiAllCheckinsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
checkins := core.AllCheckins()
|
||||
for _, c := range checkins {
|
||||
c.Hits = c.AllHits()
|
||||
c.Failures = c.AllFailures()
|
||||
c.Failures = c.LimitedFailures(64)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
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)
|
||||
return
|
||||
}
|
||||
checkin.Hits = checkin.AllHits()
|
||||
checkin.Failures = checkin.AllFailures()
|
||||
checkin.Hits = checkin.LimitedHits(32)
|
||||
checkin.Failures = checkin.LimitedFailures(32)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(checkin)
|
||||
}
|
||||
|
@ -69,6 +70,11 @@ func checkinCreateHandler(w http.ResponseWriter, r *http.Request) {
|
|||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
service := core.SelectService(checkin.ServiceId)
|
||||
if service == nil {
|
||||
sendErrorJson(fmt.Errorf("missing service_id field"), w, r)
|
||||
return
|
||||
}
|
||||
_, err = checkin.Create()
|
||||
if err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
|
@ -85,20 +91,25 @@ func checkinHitHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
ip, _, _ := net.SplitHostPort(r.RemoteAddr)
|
||||
checkinHit := core.ReturnCheckinHit(&types.CheckinHit{
|
||||
|
||||
hit := &types.CheckinHit{
|
||||
Checkin: checkin.Id,
|
||||
From: ip,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
})
|
||||
}
|
||||
checkinHit := core.ReturnCheckinHit(hit)
|
||||
if checkin.Last() == nil {
|
||||
checkin.Start()
|
||||
go checkin.Routine()
|
||||
}
|
||||
_, err := checkinHit.Create()
|
||||
checkin.Hits = append(checkin.Hits, checkinHit.CheckinHit)
|
||||
if err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
checkin.Failing = false
|
||||
checkin.LastHit = utils.Timezoner(time.Now().UTC(), core.CoreApp.Timezone)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
sendJsonAction(checkinHit, "update", w, r)
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ import (
|
|||
func dashboardHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !IsAuthenticated(r) {
|
||||
err := core.ErrorResponse{}
|
||||
ExecuteResponse(w, r, "login.html", err, nil)
|
||||
ExecuteResponse(w, r, "login.gohtml", err, nil)
|
||||
} 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)
|
||||
} else {
|
||||
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
|
||||
}
|
||||
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) {
|
||||
|
@ -84,7 +84,7 @@ func logsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
logs = append(logs, utils.LastLines[i].FormatForHtml()+"\r\n")
|
||||
}
|
||||
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) {
|
||||
|
|
|
@ -198,7 +198,7 @@ func ExecuteResponse(w http.ResponseWriter, r *http.Request, file string, data i
|
|||
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"}
|
||||
|
||||
|
@ -275,5 +275,5 @@ func executeJSResponse(w http.ResponseWriter, r *http.Request, file string, data
|
|||
// error404Handler is a HTTP handler for 404 error pages
|
||||
func error404Handler(w http.ResponseWriter, r *http.Request) {
|
||||
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)
|
||||
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) {
|
||||
|
@ -41,7 +41,7 @@ func healthCheckHandler(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
|
||||
|
|
|
@ -31,7 +31,7 @@ func messagesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
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) {
|
||||
|
@ -46,7 +46,7 @@ func viewMessageHandler(w http.ResponseWriter, r *http.Request) {
|
|||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
ExecuteResponse(w, r, "message.html", message, nil)
|
||||
ExecuteResponse(w, r, "message.gohtml", message, nil)
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ func TestApiUpdateServiceHandler(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)
|
||||
body := rr.Body.String()
|
||||
var obj apiResponse
|
||||
|
@ -270,7 +270,7 @@ func TestApiRenewHandler(t *testing.T) {
|
|||
func TestApiCheckinHandler(t *testing.T) {
|
||||
t.SkipNow()
|
||||
service := core.SelectService(1)
|
||||
checkin := service.Checkins()
|
||||
checkin := service.AllCheckins()
|
||||
rr, err := httpRequestAPI(t, "GET", "/api/checkin/"+checkin[0].ApiKey, nil)
|
||||
assert.Nil(t, err)
|
||||
body := rr.Body.String()
|
||||
|
|
|
@ -51,7 +51,7 @@ func servicesHandler(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
ExecuteResponse(w, r, "services.html", core.CoreApp.Services, nil)
|
||||
ExecuteResponse(w, r, "services.gohtml", core.CoreApp.Services, nil)
|
||||
}
|
||||
|
||||
type serviceOrder struct {
|
||||
|
@ -115,7 +115,7 @@ func servicesViewHandler(w http.ResponseWriter, r *http.Request) {
|
|||
Data string
|
||||
}{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) {
|
||||
|
@ -124,14 +124,13 @@ func apiServiceHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
servicer := core.SelectServicer(utils.ToInt(vars["id"]))
|
||||
servicer := core.SelectService(utils.ToInt(vars["id"]))
|
||||
if servicer == nil {
|
||||
sendErrorJson(errors.New("service not found"), w, r)
|
||||
return
|
||||
}
|
||||
service := servicer.Select()
|
||||
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) {
|
||||
|
@ -161,8 +160,8 @@ func apiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
service := core.SelectServicer(utils.ToInt(vars["id"]))
|
||||
if service.Select() == nil {
|
||||
service := core.SelectService(utils.ToInt(vars["id"]))
|
||||
if service == nil {
|
||||
sendErrorJson(errors.New("service not found"), w, r)
|
||||
return
|
||||
}
|
||||
|
@ -256,5 +255,5 @@ func servicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
|
|||
vars := mux.Vars(r)
|
||||
service := core.SelectService(utils.ToInt(vars["id"]))
|
||||
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)
|
||||
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) {
|
||||
|
@ -73,7 +73,7 @@ func saveSettingsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
utils.Log(3, fmt.Sprintf("issue updating Core: %v", err.Error()))
|
||||
}
|
||||
//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) {
|
||||
|
@ -90,7 +90,7 @@ func saveSASSHandler(w http.ResponseWriter, r *http.Request) {
|
|||
source.SaveAsset([]byte(mobile), utils.Directory, "scss/mobile.scss")
|
||||
source.CompileSASS(utils.Directory)
|
||||
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) {
|
||||
|
@ -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.")
|
||||
}
|
||||
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) {
|
||||
|
@ -121,7 +121,7 @@ func deleteAssetsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
source.DeleteAllAssets(utils.Directory)
|
||||
resetRouter()
|
||||
ExecuteResponse(w, r, "settings.html", core.CoreApp, "/settings")
|
||||
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "/settings")
|
||||
}
|
||||
|
||||
func parseId(r *http.Request) int64 {
|
||||
|
|
|
@ -34,7 +34,7 @@ func setupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
data, _ = core.LoadUsingEnv()
|
||||
}
|
||||
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) {
|
||||
|
@ -126,5 +126,5 @@ func processSetupHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
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) {
|
||||
|
@ -44,7 +44,7 @@ func usersEditHandler(w http.ResponseWriter, r *http.Request) {
|
|||
vars := mux.Vars(r)
|
||||
id, _ := strconv.Atoi(vars["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) {
|
||||
|
|
|
@ -33,7 +33,7 @@ var mobile = &mobilePush{¬ifier.Notification{
|
|||
Method: "mobile",
|
||||
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.
|
||||
<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",
|
||||
AuthorUrl: "https://github.com/hunterlong",
|
||||
Delay: time.Duration(5 * time.Second),
|
||||
|
|
|
@ -104,7 +104,7 @@ func TestSlackNotifier(t *testing.T) {
|
|||
slacker.OnSuccess(TestService)
|
||||
assert.Equal(t, 1, len(slacker.Queue))
|
||||
go notifier.Queue(slacker)
|
||||
time.Sleep(5 * time.Second)
|
||||
time.Sleep(6 * time.Second)
|
||||
assert.Equal(t, 0, len(slacker.Queue))
|
||||
})
|
||||
|
||||
|
|
|
@ -135,11 +135,11 @@ func CreateAllAssets(folder string) error {
|
|||
MakePublicFolder(folder + "/assets/font")
|
||||
MakePublicFolder(folder + "/assets/files")
|
||||
utils.Log(1, "Inserting scss, css, and javascript files into assets folder")
|
||||
CopyAllToPublic(ScssBox, "scss")
|
||||
CopyAllToPublic(FontBox, "font")
|
||||
CopyAllToPublic(CssBox, "css")
|
||||
CopyAllToPublic(JsBox, "js")
|
||||
CopyToPublic(FontBox, folder+"/assets/font", "all.css")
|
||||
CopyAllToPublic(ScssBox, "scss/")
|
||||
CopyAllToPublic(FontBox, "font/")
|
||||
CopyAllToPublic(CssBox, "css/")
|
||||
CopyAllToPublic(JsBox, "js/")
|
||||
CopyToPublic(FontBox, folder+"/assets/font/", "all.css")
|
||||
CopyToPublic(TmplBox, folder+"/assets", "robots.txt")
|
||||
CopyToPublic(TmplBox, folder+"/assets", "banner.png")
|
||||
CopyToPublic(TmplBox, folder+"/assets", "favicon.ico")
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"info": {
|
||||
"_postman_id": "d74ac4a3-8915-46e8-8ed2-5044ea4ce53b",
|
||||
"name": "Statping",
|
||||
"description": "Statping API Requests",
|
||||
"name": "Statup",
|
||||
"description": "Statup API Requests",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
|
@ -10,7 +10,7 @@
|
|||
"name": "Main",
|
||||
"item": [
|
||||
{
|
||||
"name": "Statping Details",
|
||||
"name": "Statup Details",
|
||||
"event": [
|
||||
{
|
||||
"listen": "test",
|
||||
|
@ -164,7 +164,7 @@
|
|||
],
|
||||
"body": {
|
||||
"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": {
|
||||
"raw": "{{endpoint}}/api/services/1",
|
||||
|
@ -250,7 +250,7 @@
|
|||
"pm.test(\"Create Service\", function () {",
|
||||
" var jsonData = pm.response.json();",
|
||||
" 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.method).to.eql(\"GET\");",
|
||||
" pm.expect(jsonData.output.expected_status).to.eql(200);",
|
||||
|
@ -280,7 +280,7 @@
|
|||
],
|
||||
"body": {
|
||||
"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": {
|
||||
"raw": "{{endpoint}}/api/services",
|
||||
|
@ -439,14 +439,14 @@
|
|||
"header": [],
|
||||
"body": {},
|
||||
"url": {
|
||||
"raw": "{{endpoint}}/api/services/1",
|
||||
"raw": "{{endpoint}}/api/services/2",
|
||||
"host": [
|
||||
"{{endpoint}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"services",
|
||||
"1"
|
||||
"2"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
@ -75,15 +75,15 @@
|
|||
{{end}}
|
||||
|
||||
{{if Auth}}
|
||||
{{$failures := $s.LimitedFailures 16}}
|
||||
<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" 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="response-tab" data-toggle="tab" href="#response" role="tab" aria-controls="response" aria-selected="false">Response</a>
|
||||
</nav>
|
||||
<div class="tab-content" id="myTabContent">
|
||||
<div class="tab-pane fade" id="failures" role="serviceLists" aria-labelledby="failures-tab">
|
||||
{{$failures := $s.LimitedFailures 16}}
|
||||
{{ if $failures }}
|
||||
<div class="list-group mt-3 mb-4">
|
||||
{{ range $failures }}
|
||||
|
@ -99,7 +99,7 @@
|
|||
{{ end }}
|
||||
</div>
|
||||
<div class="tab-pane fade" id="checkins" role="serviceLists" aria-labelledby="checkins-tab">
|
||||
{{if $s.LimitedCheckins}}
|
||||
{{if $s.AllCheckins}}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -111,7 +111,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody style="font-size: 10pt;">
|
||||
{{range $s.LimitedCheckins}}
|
||||
{{range $s.AllCheckins}}
|
||||
{{ $ch := . }}
|
||||
<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>
|
|
@ -21,23 +21,29 @@ import (
|
|||
|
||||
// Checkin struct will allow an application to send a recurring HTTP GET to confirm a service is online
|
||||
type Checkin struct {
|
||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||
ServiceId int64 `gorm:"index;column:service" json:"service_id"`
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
Interval int64 `gorm:"column:check_interval" json:"interval"`
|
||||
GracePeriod int64 `gorm:"column:grace_period" json:"grace"`
|
||||
ApiKey string `gorm:"column:api_key" json:"api_key"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
Running chan bool `gorm:"-" json:"-"`
|
||||
Hits []*CheckinHit `gorm:"-" json:"hits"`
|
||||
Failures []*Failure `gorm:"-" json:"failures"`
|
||||
Id int64 `gorm:"primary_key;column:id" json:"id"`
|
||||
ServiceId int64 `gorm:"index;column:service" json:"service_id"`
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
Interval int64 `gorm:"column:check_interval" json:"interval"`
|
||||
GracePeriod int64 `gorm:"column:grace_period" json:"grace"`
|
||||
ApiKey string `gorm:"column:api_key" json:"api_key"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
|
||||
Running chan bool `gorm:"-" json:"-"`
|
||||
Failing bool `gorm:"-" json:"failing"`
|
||||
LastHit time.Time `gorm:"-" json:"last_hit"`
|
||||
Hits []*CheckinHit `gorm:"-" json:"hits"`
|
||||
Failures []FailureInterface `gorm:"-" json:"failures"`
|
||||
}
|
||||
|
||||
type CheckinInterface interface {
|
||||
Select() *Checkin
|
||||
}
|
||||
|
||||
// CheckinHit is a successful response from a Checkin
|
||||
type CheckinHit struct {
|
||||
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"`
|
||||
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"`
|
||||
MethodId int64 `gorm:"column:method_id" json:"method_id,omitempty"`
|
||||
Service int64 `gorm:"index;column:service" json:"-"`
|
||||
Checkin int64 `gorm:"index;column:checkin" json:"-"`
|
||||
PingTime float64 `gorm:"column:ping_time" json:"ping"`
|
||||
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
|
||||
}
|
||||
|
|
|
@ -46,8 +46,9 @@ type Service struct {
|
|||
SleepDuration time.Duration `gorm:"-" json:"-"`
|
||||
LastResponse string `gorm:"-" json:"-"`
|
||||
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"`
|
||||
Checkins []CheckinInterface `gorm:"-" json:"checkins,omitempty"`
|
||||
}
|
||||
|
||||
type ServiceInterface interface {
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.79.97
|
||||
0.79.98
|
Loading…
Reference in New Issue