mirror of https://github.com/statping/statping
				
				
				
			Merge branch 'master' into feature/calculate-sleep-interval
						commit
						722d787da4
					
				| 
						 | 
				
			
			@ -14,9 +14,11 @@ assets
 | 
			
		|||
*.log
 | 
			
		||||
.env
 | 
			
		||||
logs
 | 
			
		||||
dev/test/node_modules
 | 
			
		||||
/dev/test/node_modules
 | 
			
		||||
dev/test/cypress/videos
 | 
			
		||||
dev/test/cypress/screenshots
 | 
			
		||||
dev/test/app
 | 
			
		||||
source/rice-box.go
 | 
			
		||||
sass
 | 
			
		||||
sass
 | 
			
		||||
.DS_Store
 | 
			
		||||
source/css/base.css.map
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,7 @@ before_script:
 | 
			
		|||
 | 
			
		||||
script:
 | 
			
		||||
  - make test-all
 | 
			
		||||
  - if [[ "$TRAVIS_BRANCH" == "master" ]]; then make coverage; fi
 | 
			
		||||
  - if [[ "$TRAVIS_BRANCH" == "master" && "$TRAVIS_PULL_REQUEST" = "false" ]]; then make coverage; fi
 | 
			
		||||
 | 
			
		||||
after_success:
 | 
			
		||||
  - if [[ "$TRAVIS_BRANCH" == "master" ]]; then make travis-build; fi
 | 
			
		||||
  - if [[ "$TRAVIS_BRANCH" == "master" && "$TRAVIS_PULL_REQUEST" = "false" ]]; then make travis-build; fi
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										34
									
								
								Makefile
								
								
								
								
							| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
VERSION=0.46
 | 
			
		||||
VERSION=0.47
 | 
			
		||||
BINARY_NAME=statup
 | 
			
		||||
GOPATH:=$(GOPATH)
 | 
			
		||||
GOCMD=go
 | 
			
		||||
| 
						 | 
				
			
			@ -72,10 +72,10 @@ docker-run: docker
 | 
			
		|||
docker-dev: clean
 | 
			
		||||
	docker build -t hunterlong/statup:dev -f dev/Dockerfile-dev .
 | 
			
		||||
 | 
			
		||||
docker-push-dev: docker-base docker-dev docker-test
 | 
			
		||||
docker-push-dev: docker-base docker-dev docker-cypress
 | 
			
		||||
	docker push hunterlong/statup:dev
 | 
			
		||||
	docker push hunterlong/statup:base
 | 
			
		||||
	docker push hunterlong/statup:test
 | 
			
		||||
	docker push hunterlong/statup:cypress
 | 
			
		||||
 | 
			
		||||
docker-push-latest: docker
 | 
			
		||||
	docker push hunterlong/statup:latest
 | 
			
		||||
| 
						 | 
				
			
			@ -83,15 +83,17 @@ docker-push-latest: docker
 | 
			
		|||
docker-run-dev: docker-dev
 | 
			
		||||
	docker run -t -p 8080:8080 hunterlong/statup:dev
 | 
			
		||||
 | 
			
		||||
docker-test: docker-dev clean
 | 
			
		||||
	docker build -t hunterlong/statup:test -f dev/Dockerfile-test .
 | 
			
		||||
docker-cypress: clean
 | 
			
		||||
	GOPATH=$(GOPATH) xgo -out statup -go 1.10.x -ldflags "-X main.VERSION=$(VERSION) -X main.COMMIT=$(TRAVIS_COMMIT)" --targets=linux/amd64 ./cmd
 | 
			
		||||
	docker build -t hunterlong/statup:cypress -f dev/Dockerfile-cypress .
 | 
			
		||||
	rm -f statup
 | 
			
		||||
 | 
			
		||||
docker-run-test: docker-test
 | 
			
		||||
	docker run -t -p 8080:8080 --entrypoint "go test -v -p=1 $(BUILDVERSION) ./..." hunterlong/statup:test
 | 
			
		||||
docker-run-cypress: docker-cypress
 | 
			
		||||
	docker run -t hunterlong/statup:cypress
 | 
			
		||||
 | 
			
		||||
docker-base: clean
 | 
			
		||||
	wget -q https://assets.statup.io/sass && chmod +x sass
 | 
			
		||||
	$(XGO) --targets=linux/amd64 -ldflags="-X main.VERSION=$(VERSION) -X main.COMMIT=$(TRAVIS_COMMIT) -linkmode external -extldflags -static" -out alpine ./cmd
 | 
			
		||||
	$(XGO) --targets=linux/amd64 -ldflags="-X main.VERSION=$(VERSION) -linkmode external -extldflags -static" -out alpine ./cmd
 | 
			
		||||
	docker build -t hunterlong/statup:base -f dev/Dockerfile-base .
 | 
			
		||||
 | 
			
		||||
docker-build-base:
 | 
			
		||||
| 
						 | 
				
			
			@ -124,13 +126,13 @@ dev-deps: dep
 | 
			
		|||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -rf ./{logs,assets,plugins,statup.db,config.yml,.sass-cache,config.yml,statup,build}
 | 
			
		||||
	rm -rf cmd/{logs,assets,plugins,statup.db,config.yml,.sass-cache}
 | 
			
		||||
	rm -rf core/{logs,assets,plugins,statup.db,config.yml,.sass-cache}
 | 
			
		||||
	rm -rf handlers/{logs,assets,plugins,statup.db,config.yml,.sass-cache}
 | 
			
		||||
	rm -rf notifiers/{logs,assets,plugins,statup.db,config.yml,.sass-cache}
 | 
			
		||||
	rm -rf source/{logs,assets,plugins,statup.db,config.yml,.sass-cache}
 | 
			
		||||
	rm -rf types/{logs,assets,plugins,statup.db,config.yml,.sass-cache}
 | 
			
		||||
	rm -rf utils/{logs,assets,plugins,statup.db,config.yml,.sass-cache}
 | 
			
		||||
	rm -rf cmd/{logs,assets,plugins,statup.db,config.yml,.sass-cache,*.log}
 | 
			
		||||
	rm -rf core/{logs,assets,plugins,statup.db,config.yml,.sass-cache,*.log}
 | 
			
		||||
	rm -rf handlers/{logs,assets,plugins,statup.db,config.yml,.sass-cache,*.log}
 | 
			
		||||
	rm -rf notifiers/{logs,assets,plugins,statup.db,config.yml,.sass-cache,*.log}
 | 
			
		||||
	rm -rf source/{logs,assets,plugins,statup.db,config.yml,.sass-cache,*.log}
 | 
			
		||||
	rm -rf types/{logs,assets,plugins,statup.db,config.yml,.sass-cache,*.log}
 | 
			
		||||
	rm -rf utils/{logs,assets,plugins,statup.db,config.yml,.sass-cache,*.log}
 | 
			
		||||
	rm -rf dev/test/cypress/videos
 | 
			
		||||
	rm -rf .sass-cache
 | 
			
		||||
	rm -f coverage.out
 | 
			
		||||
| 
						 | 
				
			
			@ -167,7 +169,7 @@ publish-homebrew:
 | 
			
		|||
	curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -H "Travis-API-Version: 3" -H "Authorization: token $(TRAVIS_API)" -d $(PUBLISH_BODY) https://api.travis-ci.com/repo/hunterlong%2Fhomebrew-statup/requests
 | 
			
		||||
 | 
			
		||||
cypress-install:
 | 
			
		||||
	cd /test && npm install
 | 
			
		||||
	cd dev/test && npm install
 | 
			
		||||
 | 
			
		||||
cypress-test: clean cypress-install
 | 
			
		||||
	cd dev/test && npm test
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								cmd/cli.go
								
								
								
								
							
							
						
						
									
										34
									
								
								cmd/cli.go
								
								
								
								
							| 
						 | 
				
			
			@ -132,7 +132,7 @@ func RunOnce() {
 | 
			
		|||
	if err != nil {
 | 
			
		||||
		utils.Log(4, "config.yml file not found")
 | 
			
		||||
	}
 | 
			
		||||
	err = core.DbConnection(core.Configs.Connection, false, ".")
 | 
			
		||||
	err = core.DbConnection(core.Configs.Connection, false, utils.Directory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -140,12 +140,12 @@ func RunOnce() {
 | 
			
		|||
	if err != nil {
 | 
			
		||||
		fmt.Println("Core database was not found, Statup is not setup yet.")
 | 
			
		||||
	}
 | 
			
		||||
	core.CoreApp.Services, err = core.SelectAllServices()
 | 
			
		||||
	core.CoreApp.SelectAllServices()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
	}
 | 
			
		||||
	for _, s := range core.CoreApp.Services {
 | 
			
		||||
		out := core.ServiceCheck(s, true)
 | 
			
		||||
	for _, s := range core.CoreApp.DbServices {
 | 
			
		||||
		out := core.ServiceCheck(core.ReturnService(s), true)
 | 
			
		||||
		fmt.Printf("    Service %v | URL: %v | Latency: %0.0fms | Online: %v\n", out.Name, out.Domain, (out.Latency * 1000), out.Online)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -194,7 +194,7 @@ func TestPlugin(plug types.PluginActions) {
 | 
			
		|||
	core.OnSuccess(core.SelectService(1))
 | 
			
		||||
	fmt.Println("\n" + BRAKER)
 | 
			
		||||
	fmt.Println(POINT + "Sending 'OnFailure(Service, FailureData)'")
 | 
			
		||||
	fakeFailD := core.FailureData{
 | 
			
		||||
	fakeFailD := &types.Failure{
 | 
			
		||||
		Issue: "No issue, just testing this plugin. This would include HTTP failure information though",
 | 
			
		||||
	}
 | 
			
		||||
	core.OnFailure(core.SelectService(1), fakeFailD)
 | 
			
		||||
| 
						 | 
				
			
			@ -260,14 +260,14 @@ func FakeSeed(plug types.PluginActions) {
 | 
			
		|||
		Domain: "https://google.com",
 | 
			
		||||
		Method: "GET",
 | 
			
		||||
	}}
 | 
			
		||||
	core.CreateService(fakeSrv)
 | 
			
		||||
	fakeSrv.Create()
 | 
			
		||||
 | 
			
		||||
	fakeSrv2 := &core.Service{Service: &types.Service{
 | 
			
		||||
		Name:   "Awesome Plugin Service",
 | 
			
		||||
		Domain: "https://netflix.com",
 | 
			
		||||
		Method: "GET",
 | 
			
		||||
	}}
 | 
			
		||||
	core.CreateService(fakeSrv2)
 | 
			
		||||
	fakeSrv2.Create()
 | 
			
		||||
 | 
			
		||||
	fakeUser := &types.User{
 | 
			
		||||
		Id:        6334,
 | 
			
		||||
| 
						 | 
				
			
			@ -277,7 +277,7 @@ func FakeSeed(plug types.PluginActions) {
 | 
			
		|||
		Admin:     true,
 | 
			
		||||
		CreatedAt: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
	core.CreateUser(fakeUser)
 | 
			
		||||
	fakeUser.Create()
 | 
			
		||||
 | 
			
		||||
	fakeUser = &types.User{
 | 
			
		||||
		Id:        6335,
 | 
			
		||||
| 
						 | 
				
			
			@ -286,28 +286,28 @@ func FakeSeed(plug types.PluginActions) {
 | 
			
		|||
		Email:     "info@awesome.com",
 | 
			
		||||
		CreatedAt: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
	core.CreateUser(fakeUser)
 | 
			
		||||
	fakeUser.Create()
 | 
			
		||||
 | 
			
		||||
	for i := 0; i <= 50; i++ {
 | 
			
		||||
		dd := core.HitData{
 | 
			
		||||
		dd := &types.Hit{
 | 
			
		||||
			Latency: rand.Float64(),
 | 
			
		||||
		}
 | 
			
		||||
		core.CreateServiceHit(fakeSrv, dd)
 | 
			
		||||
		fakeSrv.CreateHit(dd)
 | 
			
		||||
 | 
			
		||||
		dd = core.HitData{
 | 
			
		||||
		dd = &types.Hit{
 | 
			
		||||
			Latency: rand.Float64(),
 | 
			
		||||
		}
 | 
			
		||||
		core.CreateServiceHit(fakeSrv2, dd)
 | 
			
		||||
		fakeSrv2.CreateHit(dd)
 | 
			
		||||
 | 
			
		||||
		fail := core.FailureData{
 | 
			
		||||
		fail := &types.Failure{
 | 
			
		||||
			Issue: "This is not an issue, but it would container HTTP response errors.",
 | 
			
		||||
		}
 | 
			
		||||
		core.CreateServiceFailure(fakeSrv, fail)
 | 
			
		||||
		fakeSrv.CreateFailure(fail)
 | 
			
		||||
 | 
			
		||||
		fail = core.FailureData{
 | 
			
		||||
		fail = &types.Failure{
 | 
			
		||||
			Issue: "HTTP Status Code 521 did not match 200",
 | 
			
		||||
		}
 | 
			
		||||
		core.CreateServiceFailure(fakeSrv, fail)
 | 
			
		||||
		fakeSrv.CreateFailure(fail)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("Seeding example data is complete, running Plugin Tests")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,7 +95,7 @@ func LoadDotEnvs() error {
 | 
			
		|||
 | 
			
		||||
func mainProcess() {
 | 
			
		||||
	var err error
 | 
			
		||||
	err = core.DbConnection(core.Configs.Connection, false, ".")
 | 
			
		||||
	err = core.DbConnection(core.Configs.Connection, false, utils.Directory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, fmt.Sprintf("could not connect to database: %v", err))
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,7 +85,7 @@ func TestRunAll(t *testing.T) {
 | 
			
		|||
		t.Run(dbt+" Select Core", func(t *testing.T) {
 | 
			
		||||
			RunSelectCoreMYQL(t, dbt)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Select Services", func(t *testing.T) {
 | 
			
		||||
		t.Run(dbt+" Select DbServices", func(t *testing.T) {
 | 
			
		||||
			RunSelectAllMysqlServices(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Select Comms", func(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +104,7 @@ func TestRunAll(t *testing.T) {
 | 
			
		|||
		t.Run(dbt+" Select Users", func(t *testing.T) {
 | 
			
		||||
			RunUser_SelectAll(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Select Services", func(t *testing.T) {
 | 
			
		||||
		t.Run(dbt+" Select DbServices", func(t *testing.T) {
 | 
			
		||||
			RunSelectAllServices(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Select One Service", func(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -116,6 +116,9 @@ func TestRunAll(t *testing.T) {
 | 
			
		|||
		t.Run(dbt+" Create Hits", func(t *testing.T) {
 | 
			
		||||
			RunCreateService_Hits(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Service ToJSON()", func(t *testing.T) {
 | 
			
		||||
			RunService_ToJSON(t)
 | 
			
		||||
		})
 | 
			
		||||
		t.Run(dbt+" Avg Time", func(t *testing.T) {
 | 
			
		||||
			RunService_AvgTime(t)
 | 
			
		||||
		})
 | 
			
		||||
| 
						 | 
				
			
			@ -208,7 +211,7 @@ func RunMakeDatabaseConfig(t *testing.T, db string) {
 | 
			
		|||
	//Error       error  `yaml:"-"`
 | 
			
		||||
	//Location    string `yaml:"location"`
 | 
			
		||||
 | 
			
		||||
	config := &core.DbConfig{DbConfig: &types.DbConfig{
 | 
			
		||||
	config := &core.DbConfig{&types.DbConfig{
 | 
			
		||||
		DbConn:      db,
 | 
			
		||||
		DbHost:      os.Getenv("DB_HOST"),
 | 
			
		||||
		DbUser:      os.Getenv("DB_USER"),
 | 
			
		||||
| 
						 | 
				
			
			@ -265,7 +268,7 @@ func RunSelectCoreMYQL(t *testing.T, db string) {
 | 
			
		|||
 | 
			
		||||
func RunSelectAllMysqlServices(t *testing.T) {
 | 
			
		||||
	var err error
 | 
			
		||||
	services, err := core.SelectAllServices()
 | 
			
		||||
	services, err := core.CoreApp.SelectAllServices()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 5, len(services))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -285,22 +288,22 @@ func RunUser_SelectAll(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func RunUser_Create(t *testing.T) {
 | 
			
		||||
	user := &types.User{
 | 
			
		||||
	user := core.ReturnUser(&types.User{
 | 
			
		||||
		Username: "admin",
 | 
			
		||||
		Password: "admin",
 | 
			
		||||
		Email:    "info@testuser.com",
 | 
			
		||||
		Admin:    true,
 | 
			
		||||
	}
 | 
			
		||||
	id, err := core.CreateUser(user)
 | 
			
		||||
	})
 | 
			
		||||
	id, err := user.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, int64(1), id)
 | 
			
		||||
	user2 := &types.User{
 | 
			
		||||
	user2 := core.ReturnUser(&types.User{
 | 
			
		||||
		Username: "superadmin",
 | 
			
		||||
		Password: "admin",
 | 
			
		||||
		Email:    "info@adminer.com",
 | 
			
		||||
		Admin:    true,
 | 
			
		||||
	}
 | 
			
		||||
	id, err = core.CreateUser(user2)
 | 
			
		||||
	})
 | 
			
		||||
	id, err = user2.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, int64(2), id)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -309,7 +312,7 @@ func RunUser_Update(t *testing.T) {
 | 
			
		|||
	user, err := core.SelectUser(1)
 | 
			
		||||
	user.Email = "info@updatedemail.com"
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	err = core.UpdateUser(user)
 | 
			
		||||
	err = user.Update()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	updatedUser, err := core.SelectUser(1)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
| 
						 | 
				
			
			@ -317,12 +320,12 @@ func RunUser_Update(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func RunUser_NonUniqueCreate(t *testing.T) {
 | 
			
		||||
	user := &types.User{
 | 
			
		||||
	user := core.ReturnUser(&types.User{
 | 
			
		||||
		Username: "admin",
 | 
			
		||||
		Password: "admin",
 | 
			
		||||
		Email:    "info@testuser.com",
 | 
			
		||||
	}
 | 
			
		||||
	admin, err := core.CreateUser(user)
 | 
			
		||||
	})
 | 
			
		||||
	admin, err := user.Create()
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	assert.Nil(t, admin)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -331,13 +334,13 @@ func RunUser_Delete(t *testing.T) {
 | 
			
		|||
	user, err := core.SelectUser(2)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotNil(t, user)
 | 
			
		||||
	err = core.DeleteUser(user)
 | 
			
		||||
	err = user.Delete()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunSelectAllServices(t *testing.T) {
 | 
			
		||||
	var err error
 | 
			
		||||
	services, err := core.SelectAllServices()
 | 
			
		||||
	services, err := core.CoreApp.SelectAllServices()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 5, len(services))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -360,12 +363,19 @@ func RunService_Create(t *testing.T) {
 | 
			
		|||
		Method:         "GET",
 | 
			
		||||
		Timeout:        30,
 | 
			
		||||
	}}
 | 
			
		||||
	id, err := core.CreateService(service)
 | 
			
		||||
	id, err := service.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, int64(6), id)
 | 
			
		||||
	t.Log(service)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunService_ToJSON(t *testing.T) {
 | 
			
		||||
	service := core.SelectService(1)
 | 
			
		||||
	assert.NotNil(t, service)
 | 
			
		||||
	jsoned := service.ToJSON()
 | 
			
		||||
	assert.NotEmpty(t, jsoned)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunService_AvgTime(t *testing.T) {
 | 
			
		||||
	service := core.SelectService(1)
 | 
			
		||||
	assert.NotNil(t, service)
 | 
			
		||||
| 
						 | 
				
			
			@ -401,7 +411,7 @@ func RunBadService_Create(t *testing.T) {
 | 
			
		|||
		Method:         "GET",
 | 
			
		||||
		Timeout:        30,
 | 
			
		||||
	}}
 | 
			
		||||
	id, err := core.CreateService(service)
 | 
			
		||||
	id, err := service.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, int64(7), id)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -422,14 +432,14 @@ func RunDeleteService(t *testing.T) {
 | 
			
		|||
	assert.Equal(t, "JSON API Tester", service.Name)
 | 
			
		||||
	assert.True(t, service.IsRunning())
 | 
			
		||||
	t.Log(service.Running)
 | 
			
		||||
	err := core.DeleteService(service)
 | 
			
		||||
	err := service.Delete()
 | 
			
		||||
	t.Log(service.Running)
 | 
			
		||||
	assert.False(t, service.IsRunning())
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RunCreateService_Hits(t *testing.T) {
 | 
			
		||||
	services, err := core.SelectAllServices()
 | 
			
		||||
	services, err := core.CoreApp.SelectAllServices()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotNil(t, services)
 | 
			
		||||
	assert.Equal(t, 6, len(services))
 | 
			
		||||
| 
						 | 
				
			
			@ -437,9 +447,9 @@ func RunCreateService_Hits(t *testing.T) {
 | 
			
		|||
		for _, s := range services {
 | 
			
		||||
			var service *core.Service
 | 
			
		||||
			if s.Type == "http" {
 | 
			
		||||
				service = core.ServiceHTTPCheck(s, true)
 | 
			
		||||
				service = core.ServiceHTTPCheck(core.ReturnService(s), true)
 | 
			
		||||
			} else {
 | 
			
		||||
				service = core.ServiceTCPCheck(s, true)
 | 
			
		||||
				service = core.ServiceTCPCheck(core.ReturnService(s), true)
 | 
			
		||||
			}
 | 
			
		||||
			assert.NotNil(t, service)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,17 +31,16 @@ import (
 | 
			
		|||
type FailureData types.FailureData
 | 
			
		||||
 | 
			
		||||
func CheckServices() {
 | 
			
		||||
	CoreApp.Services, _ = SelectAllServices()
 | 
			
		||||
	utils.Log(1, fmt.Sprintf("Starting monitoring process for %v Services", len(CoreApp.Services)))
 | 
			
		||||
	for _, s := range CoreApp.Services {
 | 
			
		||||
	CoreApp.SelectAllServices()
 | 
			
		||||
	utils.Log(1, fmt.Sprintf("Starting monitoring process for %v DbServices", len(CoreApp.DbServices)))
 | 
			
		||||
	for _, ser := range CoreApp.DbServices {
 | 
			
		||||
		//go obj.StartCheckins()
 | 
			
		||||
		go CheckQueue(s, true)
 | 
			
		||||
		s := ReturnService(ser)
 | 
			
		||||
		go s.CheckQueue(true)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CheckQueue(s *Service, record bool) {
 | 
			
		||||
	s.Checkpoint = time.Now()
 | 
			
		||||
 | 
			
		||||
func (s *Service) CheckQueue(record bool) {
 | 
			
		||||
CheckLoop:
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
| 
						 | 
				
			
			@ -194,21 +193,21 @@ type HitData struct {
 | 
			
		|||
func RecordSuccess(s *Service) {
 | 
			
		||||
	s.Online = true
 | 
			
		||||
	s.LastOnline = time.Now()
 | 
			
		||||
	data := HitData{
 | 
			
		||||
	data := &types.Hit{
 | 
			
		||||
		Latency: s.Latency,
 | 
			
		||||
	}
 | 
			
		||||
	utils.Log(1, fmt.Sprintf("Service %v Successful: %0.2f ms", s.Name, data.Latency*1000))
 | 
			
		||||
	CreateServiceHit(s, data)
 | 
			
		||||
	s.CreateHit(data)
 | 
			
		||||
	OnSuccess(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RecordFailure(s *Service, issue string) {
 | 
			
		||||
	s.Online = false
 | 
			
		||||
	data := FailureData{
 | 
			
		||||
	data := &types.Failure{
 | 
			
		||||
		Issue: issue,
 | 
			
		||||
	}
 | 
			
		||||
	utils.Log(2, fmt.Sprintf("Service %v Failing: %v", s.Name, issue))
 | 
			
		||||
	CreateServiceFailure(s, data)
 | 
			
		||||
	s.CreateFailure(data)
 | 
			
		||||
	//SendFailureEmail(s)
 | 
			
		||||
	OnFailure(s, data)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,14 +23,20 @@ import (
 | 
			
		|||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Checkin types.Checkin
 | 
			
		||||
type Checkin struct {
 | 
			
		||||
	*types.Checkin
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Checkin) String() string {
 | 
			
		||||
	return c.Api
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ReturnCheckin(s *types.Checkin) *Checkin {
 | 
			
		||||
	return &Checkin{Checkin: s}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func FindCheckin(api string) *types.Checkin {
 | 
			
		||||
	for _, ser := range CoreApp.Services {
 | 
			
		||||
	for _, ser := range CoreApp.DbServices {
 | 
			
		||||
		for _, c := range ser.Checkins {
 | 
			
		||||
			if c.Api == api {
 | 
			
		||||
				return c
 | 
			
		||||
| 
						 | 
				
			
			@ -40,7 +46,7 @@ func FindCheckin(api string) *types.Checkin {
 | 
			
		|||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectAllCheckins(s *types.Service) []*types.Checkin {
 | 
			
		||||
func (s *Service) AllCheckins() []*types.Checkin {
 | 
			
		||||
	var checkins []*types.Checkin
 | 
			
		||||
	col := DbSession.Collection("checkins").Find("service", s.Id).OrderBy("-id")
 | 
			
		||||
	col.All(&checkins)
 | 
			
		||||
| 
						 | 
				
			
			@ -116,7 +122,7 @@ func (f *Checkin) Ago() string {
 | 
			
		|||
//}
 | 
			
		||||
//
 | 
			
		||||
//func CheckinProcess() {
 | 
			
		||||
//	for _, s := range CoreApp.Services {
 | 
			
		||||
//	for _, s := range CoreApp.DbServices {
 | 
			
		||||
//		for _, c := range s.Checkins {
 | 
			
		||||
//			checkin := c
 | 
			
		||||
//			go checkin.Run()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ func LoadConfig() (*types.Config, error) {
 | 
			
		|||
		return LoadUsingEnv()
 | 
			
		||||
	}
 | 
			
		||||
	Configs = new(types.Config)
 | 
			
		||||
	file, err := ioutil.ReadFile("config.yml")
 | 
			
		||||
	file, err := ioutil.ReadFile(utils.Directory + "/config.yml")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("config.yml file not found - starting in setup mode")
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +74,7 @@ func LoadUsingEnv() (*types.Config, error) {
 | 
			
		|||
		CoreApp.UseCdn = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dbConfig := &DbConfig{DbConfig: &types.DbConfig{
 | 
			
		||||
	dbConfig := &DbConfig{&types.DbConfig{
 | 
			
		||||
		DbConn:      os.Getenv("DB_CONN"),
 | 
			
		||||
		DbHost:      os.Getenv("DB_HOST"),
 | 
			
		||||
		DbUser:      os.Getenv("DB_USER"),
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +89,7 @@ func LoadUsingEnv() (*types.Config, error) {
 | 
			
		|||
		Email:       "info@localhost.com",
 | 
			
		||||
	}}
 | 
			
		||||
 | 
			
		||||
	err := DbConnection(dbConfig.DbConn, true, ".")
 | 
			
		||||
	err := DbConnection(dbConfig.DbConn, true, utils.Directory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
		return nil, err
 | 
			
		||||
| 
						 | 
				
			
			@ -125,7 +125,7 @@ func LoadUsingEnv() (*types.Config, error) {
 | 
			
		|||
			Email:    "info@admin.com",
 | 
			
		||||
			Admin:    true,
 | 
			
		||||
		}
 | 
			
		||||
		CreateUser(admin)
 | 
			
		||||
		admin.Create()
 | 
			
		||||
 | 
			
		||||
		LoadSampleData()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										17
									
								
								core/core.go
								
								
								
								
							
							
						
						
									
										17
									
								
								core/core.go
								
								
								
								
							| 
						 | 
				
			
			@ -30,7 +30,6 @@ type PluginRepos types.PluginRepos
 | 
			
		|||
 | 
			
		||||
type Core struct {
 | 
			
		||||
	*types.Core
 | 
			
		||||
	Services []*Service
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
| 
						 | 
				
			
			@ -64,7 +63,7 @@ func (c *Core) ToCore() *types.Core {
 | 
			
		|||
func InitApp() {
 | 
			
		||||
	SelectCore()
 | 
			
		||||
	InsertNotifierDB()
 | 
			
		||||
	SelectAllServices()
 | 
			
		||||
	CoreApp.SelectAllServices()
 | 
			
		||||
	CheckServices()
 | 
			
		||||
	CoreApp.Communications = notifiers.Load()
 | 
			
		||||
	go DatabaseMaintence()
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +71,7 @@ func InitApp() {
 | 
			
		|||
 | 
			
		||||
func InsertNotifierDB() error {
 | 
			
		||||
	if DbSession == nil {
 | 
			
		||||
		err := DbConnection(CoreApp.DbConnection, false, ".")
 | 
			
		||||
		err := DbConnection(CoreApp.DbConnection, false, utils.Directory)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.New("database connection has not been created")
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +112,7 @@ func (c Core) MobileSASS() string {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (c Core) AllOnline() bool {
 | 
			
		||||
	for _, s := range CoreApp.Services {
 | 
			
		||||
	for _, s := range CoreApp.DbServices {
 | 
			
		||||
		if !s.Online {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -146,10 +145,18 @@ func SelectCore() (*Core, error) {
 | 
			
		|||
	CoreApp.Core = c
 | 
			
		||||
	CoreApp.DbConnection = Configs.Connection
 | 
			
		||||
	CoreApp.Version = VERSION
 | 
			
		||||
	CoreApp.Services, _ = SelectAllServices()
 | 
			
		||||
	CoreApp.SelectAllServices()
 | 
			
		||||
	if os.Getenv("USE_CDN") == "true" {
 | 
			
		||||
		CoreApp.UseCdn = true
 | 
			
		||||
	}
 | 
			
		||||
	//store = sessions.NewCookieStore([]byte(core.ApiSecret))
 | 
			
		||||
	return CoreApp, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Core) Services() []*Service {
 | 
			
		||||
	var services []*Service
 | 
			
		||||
	for _, ser := range CoreApp.DbServices {
 | 
			
		||||
		services = append(services, ReturnService(ser))
 | 
			
		||||
	}
 | 
			
		||||
	return services
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ func TestNewCore(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestDbConfig_Save(t *testing.T) {
 | 
			
		||||
	testConfig = &DbConfig{DbConfig: &types.DbConfig{
 | 
			
		||||
	testConfig = &DbConfig{&types.DbConfig{
 | 
			
		||||
		DbConn:   "sqlite",
 | 
			
		||||
		Project:  "Tester",
 | 
			
		||||
		Location: dir,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -104,7 +104,7 @@ func DbConnection(dbType string, retry bool, location string) error {
 | 
			
		|||
 | 
			
		||||
func waitForDb(dbType string) error {
 | 
			
		||||
	time.Sleep(5 * time.Second)
 | 
			
		||||
	return DbConnection(dbType, true, ".")
 | 
			
		||||
	return DbConnection(dbType, true, utils.Directory)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DatabaseMaintence() {
 | 
			
		||||
| 
						 | 
				
			
			@ -126,12 +126,12 @@ func DeleteAllSince(table string, date time.Time) {
 | 
			
		|||
 | 
			
		||||
func (c *DbConfig) Save() error {
 | 
			
		||||
	var err error
 | 
			
		||||
	config, err := os.Create("config.yml")
 | 
			
		||||
	config, err := os.Create(utils.Directory + "/config.yml")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	data, err := yaml.Marshal(c)
 | 
			
		||||
	data, err := yaml.Marshal(c.DbConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		return err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ func OnSuccess(s *Service) {
 | 
			
		|||
	// TODO convert notifiers to correct type
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func OnFailure(s *Service, f FailureData) {
 | 
			
		||||
func OnFailure(s *Service, f *types.Failure) {
 | 
			
		||||
	for _, p := range CoreApp.AllPlugins {
 | 
			
		||||
		p.OnFailure(structs.Map(s))
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +49,7 @@ func OnSettingsSaved(c *types.Core) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func OnNewUser(u *types.User) {
 | 
			
		||||
func OnNewUser(u *User) {
 | 
			
		||||
	for _, p := range CoreApp.AllPlugins {
 | 
			
		||||
		p.OnNewUser(structs.Map(u))
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ import (
 | 
			
		|||
func ExportIndexHTML() string {
 | 
			
		||||
	source.Assets()
 | 
			
		||||
	CoreApp.UseCdn = true
 | 
			
		||||
	//out := index{*CoreApp, CoreApp.Services}
 | 
			
		||||
	//out := index{*CoreApp, CoreApp.DbServices}
 | 
			
		||||
	nav, _ := source.TmplBox.String("nav.html")
 | 
			
		||||
	footer, _ := source.TmplBox.String("footer.html")
 | 
			
		||||
	render, err := source.TmplBox.String("index.html")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,17 +24,19 @@ import (
 | 
			
		|||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func CreateServiceFailure(s *Service, data FailureData) (int64, error) {
 | 
			
		||||
	fail := &types.Failure{
 | 
			
		||||
		Issue:     data.Issue,
 | 
			
		||||
		Service:   s.Id,
 | 
			
		||||
		CreatedAt: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
	s.Failures = append(s.Failures, fail)
 | 
			
		||||
type Failure struct {
 | 
			
		||||
	*types.Failure
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) CreateFailure(f *types.Failure) (int64, error) {
 | 
			
		||||
	f.CreatedAt = time.Now()
 | 
			
		||||
	f.Service = s.Id
 | 
			
		||||
	s.Failures = append(s.Failures, f)
 | 
			
		||||
	col := DbSession.Collection("failures")
 | 
			
		||||
	uuid, err := col.Insert(fail)
 | 
			
		||||
	uuid, err := col.Insert(f)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	if uuid == nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
| 
						 | 
				
			
			@ -42,12 +44,13 @@ func CreateServiceFailure(s *Service, data FailureData) (int64, error) {
 | 
			
		|||
	return uuid.(int64), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectAllFailures(s *types.Service) []*types.Failure {
 | 
			
		||||
func (s *Service) AllFailures() []*types.Failure {
 | 
			
		||||
	var fails []*types.Failure
 | 
			
		||||
	col := DbSession.Collection("failures").Find("service", s.Id).OrderBy("-id")
 | 
			
		||||
	err := col.All(&fails)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Issue getting failures for service %v, %v", s.Name, err))
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return fails
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -62,31 +65,25 @@ func DeleteFailures(u *Service) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) LimitedFailures() []*Failure {
 | 
			
		||||
	var fails []*types.Failure
 | 
			
		||||
	var failArr []*Failure
 | 
			
		||||
	col := DbSession.Collection("failures").Find("service", s.Id).OrderBy("-id").Limit(10)
 | 
			
		||||
	col.All(&fails)
 | 
			
		||||
	for _, f := range fails {
 | 
			
		||||
		failArr = append(failArr, MakeFailure(f))
 | 
			
		||||
	}
 | 
			
		||||
	col.All(&failArr)
 | 
			
		||||
	return failArr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func reverseFailures(input []*types.Failure) []*types.Failure {
 | 
			
		||||
func reverseFailures(input []*Failure) []*Failure {
 | 
			
		||||
	if len(input) == 0 {
 | 
			
		||||
		return input
 | 
			
		||||
	}
 | 
			
		||||
	return append(reverseFailures(input[1:]), input[0])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (fail *Failure) Ago() string {
 | 
			
		||||
	f := fail.ToFailure()
 | 
			
		||||
func (f *Failure) Ago() string {
 | 
			
		||||
	got, _ := timeago.TimeAgoWithTime(time.Now(), f.CreatedAt)
 | 
			
		||||
	return got
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (fail *Failure) Delete() error {
 | 
			
		||||
	f := fail.ToFailure()
 | 
			
		||||
func (f *Failure) Delete() error {
 | 
			
		||||
	col := DbSession.Collection("failures").Find("id", f.Id)
 | 
			
		||||
	return col.Delete()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -113,17 +110,7 @@ func (s *Service) TotalFailures24Hours() (uint64, error) {
 | 
			
		|||
	return amount, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *Failure) ToFailure() *types.Failure {
 | 
			
		||||
	return f.F.(*types.Failure)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func MakeFailure(f *types.Failure) *Failure {
 | 
			
		||||
	fail := &Failure{f}
 | 
			
		||||
	return fail
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (fail *Failure) ParseError() string {
 | 
			
		||||
	f := fail.ToFailure()
 | 
			
		||||
func (f *Failure) ParseError() string {
 | 
			
		||||
	err := strings.Contains(f.Issue, "operation timed out")
 | 
			
		||||
	if err {
 | 
			
		||||
		return fmt.Sprintf("HTTP Request Timed Out")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										21
									
								
								core/hits.go
								
								
								
								
							
							
						
						
									
										21
									
								
								core/hits.go
								
								
								
								
							| 
						 | 
				
			
			@ -22,18 +22,17 @@ import (
 | 
			
		|||
	"upper.io/db.v3"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Hit types.Hit
 | 
			
		||||
type Hit struct {
 | 
			
		||||
	*types.Hit
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hitCol() db.Collection {
 | 
			
		||||
	return DbSession.Collection("hits")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CreateServiceHit(s *Service, d HitData) (int64, error) {
 | 
			
		||||
	h := Hit{
 | 
			
		||||
		Service:   s.Id,
 | 
			
		||||
		Latency:   d.Latency,
 | 
			
		||||
		CreatedAt: time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
func (s *Service) CreateHit(h *types.Hit) (int64, error) {
 | 
			
		||||
	h.CreatedAt = time.Now()
 | 
			
		||||
	h.Service = s.Id
 | 
			
		||||
	uuid, err := hitCol().Insert(h)
 | 
			
		||||
	if uuid == nil {
 | 
			
		||||
		utils.Log(2, err)
 | 
			
		||||
| 
						 | 
				
			
			@ -42,8 +41,8 @@ func CreateServiceHit(s *Service, d HitData) (int64, error) {
 | 
			
		|||
	return uuid.(int64), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) Hits() ([]Hit, error) {
 | 
			
		||||
	var hits []Hit
 | 
			
		||||
func (s *Service) Hits() ([]*Hit, error) {
 | 
			
		||||
	var hits []*Hit
 | 
			
		||||
	col := hitCol().Find("service", s.Id).OrderBy("-id")
 | 
			
		||||
	err := col.All(&hits)
 | 
			
		||||
	return hits, err
 | 
			
		||||
| 
						 | 
				
			
			@ -63,8 +62,8 @@ func reverseHits(input []*Hit) []*Hit {
 | 
			
		|||
	return append(reverseHits(input[1:]), input[0])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) SelectHitsGroupBy(group string) ([]Hit, error) {
 | 
			
		||||
	var hits []Hit
 | 
			
		||||
func (s *Service) SelectHitsGroupBy(group string) ([]*Hit, error) {
 | 
			
		||||
	var hits []*Hit
 | 
			
		||||
	col := hitCol().Find("service", s.Id)
 | 
			
		||||
	err := col.All(&hits)
 | 
			
		||||
	return hits, err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										105
									
								
								core/services.go
								
								
								
								
							
							
						
						
									
										105
									
								
								core/services.go
								
								
								
								
							| 
						 | 
				
			
			@ -29,8 +29,8 @@ type Service struct {
 | 
			
		|||
	*types.Service
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Failure struct {
 | 
			
		||||
	F interface{}
 | 
			
		||||
func ReturnService(s *types.Service) *Service {
 | 
			
		||||
	return &Service{Service: s}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serviceCol() db.Collection {
 | 
			
		||||
| 
						 | 
				
			
			@ -38,32 +38,37 @@ func serviceCol() db.Collection {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func SelectService(id int64) *Service {
 | 
			
		||||
	for _, s := range CoreApp.Services {
 | 
			
		||||
	for _, s := range CoreApp.DbServices {
 | 
			
		||||
		if s.Id == id {
 | 
			
		||||
			return s
 | 
			
		||||
			return ReturnService(s)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectAllServices() ([]*Service, error) {
 | 
			
		||||
func (c *Core) SelectAllServices() ([]*types.Service, error) {
 | 
			
		||||
	var services []*types.Service
 | 
			
		||||
	var sers []*Service
 | 
			
		||||
	var servs []*types.Service
 | 
			
		||||
	col := serviceCol().Find()
 | 
			
		||||
	err := col.All(&services)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("service error: %v", err))
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	for _, s := range services {
 | 
			
		||||
		ser := NewService(s)
 | 
			
		||||
		ser.Start()
 | 
			
		||||
		ser.Checkins = SelectAllCheckins(s)
 | 
			
		||||
		ser.Failures = SelectAllFailures(s)
 | 
			
		||||
		sers = append(sers, ser)
 | 
			
		||||
	for _, ser := range services {
 | 
			
		||||
		single := ReturnService(ser)
 | 
			
		||||
		single.Start()
 | 
			
		||||
		single.AllCheckins()
 | 
			
		||||
		single.AllFailures()
 | 
			
		||||
		servs = append(servs, single.Service)
 | 
			
		||||
	}
 | 
			
		||||
	CoreApp.Services = sers
 | 
			
		||||
	return sers, err
 | 
			
		||||
	CoreApp.DbServices = servs
 | 
			
		||||
	return services, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) ToJSON() string {
 | 
			
		||||
	data, _ := json.Marshal(s)
 | 
			
		||||
	return string(data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) AvgTime() float64 {
 | 
			
		||||
| 
						 | 
				
			
			@ -104,8 +109,10 @@ type DateScan struct {
 | 
			
		|||
	Value     int64     `json:"y"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewService(s *types.Service) *Service {
 | 
			
		||||
	return &Service{s}
 | 
			
		||||
func (s *Service) lastFailure() *Failure {
 | 
			
		||||
	limited := s.LimitedFailures()
 | 
			
		||||
	last := limited[len(limited)-1]
 | 
			
		||||
	return last
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) SmallText() string {
 | 
			
		||||
| 
						 | 
				
			
			@ -119,8 +126,8 @@ func (s *Service) SmallText() string {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(last) > 0 {
 | 
			
		||||
		lastFailure := MakeFailure(last[0].ToFailure())
 | 
			
		||||
		return fmt.Sprintf("%v on %v", lastFailure.ParseError(), last[0].ToFailure().CreatedAt.Format("Monday 3:04PM, Jan _2 2006"))
 | 
			
		||||
		lastFailure := s.lastFailure()
 | 
			
		||||
		return fmt.Sprintf("%v on %v", lastFailure.ParseError(), last[0].CreatedAt.Format("Monday 3:04PM, Jan _2 2006"))
 | 
			
		||||
	} else {
 | 
			
		||||
		return fmt.Sprintf("%v is currently offline", s.Name)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -142,9 +149,7 @@ func GroupDataBy(column string, id int64, tm time.Time, increment string) string
 | 
			
		|||
func (s *Service) GraphData() string {
 | 
			
		||||
	var d []*DateScan
 | 
			
		||||
	since := time.Now().Add(time.Hour*-24 + time.Minute*0 + time.Second*0)
 | 
			
		||||
 | 
			
		||||
	sql := GroupDataBy("hits", s.Id, since, "minute")
 | 
			
		||||
 | 
			
		||||
	dated, err := DbSession.Query(db.Raw(sql))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(2, err)
 | 
			
		||||
| 
						 | 
				
			
			@ -196,18 +201,29 @@ func (s *Service) AvgUptime() string {
 | 
			
		|||
	return s.TotalUptime
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func RemoveArray(u *Service) []*Service {
 | 
			
		||||
	var srvcs []*Service
 | 
			
		||||
	for _, s := range CoreApp.Services {
 | 
			
		||||
func RemoveArray(u *Service) []*types.Service {
 | 
			
		||||
	var srvcs []*types.Service
 | 
			
		||||
	for _, s := range CoreApp.DbServices {
 | 
			
		||||
		if s.Id != u.Id {
 | 
			
		||||
			srvcs = append(srvcs, s)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	CoreApp.Services = srvcs
 | 
			
		||||
	CoreApp.DbServices = srvcs
 | 
			
		||||
	return srvcs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DeleteService(u *Service) error {
 | 
			
		||||
func updateService(new *Service) {
 | 
			
		||||
	var services []*types.Service
 | 
			
		||||
	for _, s := range CoreApp.DbServices {
 | 
			
		||||
		if s.Id == new.Id {
 | 
			
		||||
			s = new.Service
 | 
			
		||||
		}
 | 
			
		||||
		services = append(services, s)
 | 
			
		||||
	}
 | 
			
		||||
	CoreApp.DbServices = services
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (u *Service) Delete() error {
 | 
			
		||||
	res := serviceCol().Find("id", u.Id)
 | 
			
		||||
	err := res.Delete()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -220,36 +236,25 @@ func DeleteService(u *Service) error {
 | 
			
		|||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func UpdateService(service *Service) *Service {
 | 
			
		||||
	service.CreatedAt = time.Now()
 | 
			
		||||
	res := serviceCol().Find("id", service.Id)
 | 
			
		||||
	err := res.Update(service)
 | 
			
		||||
func (u *Service) Update() error {
 | 
			
		||||
	u.CreatedAt = time.Now()
 | 
			
		||||
	res := serviceCol().Find("id", u.Id)
 | 
			
		||||
	err := res.Update(u)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Failed to update service %v. %v", service.Name, err))
 | 
			
		||||
		return service
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Failed to update service %v. %v", u.Name, err))
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	updateService(service)
 | 
			
		||||
	CoreApp.Services, err = SelectAllServices()
 | 
			
		||||
	updateService(u)
 | 
			
		||||
	CoreApp.SelectAllServices()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("error selecting all services: %v", err))
 | 
			
		||||
		return service
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	OnUpdateService(service)
 | 
			
		||||
	return service
 | 
			
		||||
	OnUpdateService(u)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func updateService(new *Service) {
 | 
			
		||||
	var services []*Service
 | 
			
		||||
	for _, s := range CoreApp.Services {
 | 
			
		||||
		if s.Id == new.Id {
 | 
			
		||||
			s = new
 | 
			
		||||
		}
 | 
			
		||||
		services = append(services, s)
 | 
			
		||||
	}
 | 
			
		||||
	CoreApp.Services = services
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CreateService(u *Service) (int64, error) {
 | 
			
		||||
func (u *Service) Create() (int64, error) {
 | 
			
		||||
	u.CreatedAt = time.Now()
 | 
			
		||||
	uuid, err := serviceCol().Insert(u)
 | 
			
		||||
	if uuid == nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -258,13 +263,13 @@ func CreateService(u *Service) (int64, error) {
 | 
			
		|||
	}
 | 
			
		||||
	u.Id = uuid.(int64)
 | 
			
		||||
	u.Start()
 | 
			
		||||
	CoreApp.Services = append(CoreApp.Services, u)
 | 
			
		||||
	CoreApp.DbServices = append(CoreApp.DbServices, u.Service)
 | 
			
		||||
	return uuid.(int64), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CountOnline() int {
 | 
			
		||||
	amount := 0
 | 
			
		||||
	for _, s := range CoreApp.Services {
 | 
			
		||||
	for _, s := range CoreApp.DbServices {
 | 
			
		||||
		if s.Online {
 | 
			
		||||
			amount++
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ var (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
func TestSelectAllServices(t *testing.T) {
 | 
			
		||||
	services, err := SelectAllServices()
 | 
			
		||||
	services, err := CoreApp.SelectAllServices()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 5, len(services))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -49,19 +49,19 @@ func TestUpdateService(t *testing.T) {
 | 
			
		|||
	assert.Equal(t, "Google", service.Name)
 | 
			
		||||
	srv := service
 | 
			
		||||
	srv.Name = "Updated Google"
 | 
			
		||||
	newService := UpdateService(srv)
 | 
			
		||||
	assert.Equal(t, "Updated Google", newService.Name)
 | 
			
		||||
	err := srv.Update()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUpdateAllServices(t *testing.T) {
 | 
			
		||||
	services, err := SelectAllServices()
 | 
			
		||||
	services, err := CoreApp.SelectAllServices()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	for k, s := range services {
 | 
			
		||||
		srv := s
 | 
			
		||||
		srv := ReturnService(s)
 | 
			
		||||
		srv.Name = "Changed " + srv.Name
 | 
			
		||||
		srv.Interval = k + 3
 | 
			
		||||
		newService := UpdateService(srv)
 | 
			
		||||
		assert.Contains(t, newService.Name, "Changed")
 | 
			
		||||
		err := srv.Update()
 | 
			
		||||
		assert.Nil(t, err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -146,7 +146,7 @@ func TestCountOnline(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateService(t *testing.T) {
 | 
			
		||||
	s := &Service{Service: &types.Service{
 | 
			
		||||
	s := ReturnService(&types.Service{
 | 
			
		||||
		Name:           "That'll do 🐢",
 | 
			
		||||
		Domain:         "https://www.youtube.com/watch?v=rjQtzV9IZ0Q",
 | 
			
		||||
		ExpectedStatus: 200,
 | 
			
		||||
| 
						 | 
				
			
			@ -154,9 +154,9 @@ func TestCreateService(t *testing.T) {
 | 
			
		|||
		Type:           "http",
 | 
			
		||||
		Method:         "GET",
 | 
			
		||||
		Timeout:        20,
 | 
			
		||||
	}}
 | 
			
		||||
	})
 | 
			
		||||
	var err error
 | 
			
		||||
	newServiceId, err = CreateService(s)
 | 
			
		||||
	newServiceId, err = s.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotZero(t, newServiceId)
 | 
			
		||||
	newService := SelectService(newServiceId)
 | 
			
		||||
| 
						 | 
				
			
			@ -170,7 +170,7 @@ func TestViewNewService(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateFailingHTTPService(t *testing.T) {
 | 
			
		||||
	s := &Service{Service: &types.Service{
 | 
			
		||||
	s := ReturnService(&types.Service{
 | 
			
		||||
		Name:           "Bad URL",
 | 
			
		||||
		Domain:         "http://localhost/iamnothere",
 | 
			
		||||
		ExpectedStatus: 200,
 | 
			
		||||
| 
						 | 
				
			
			@ -178,9 +178,9 @@ func TestCreateFailingHTTPService(t *testing.T) {
 | 
			
		|||
		Type:           "http",
 | 
			
		||||
		Method:         "GET",
 | 
			
		||||
		Timeout:        5,
 | 
			
		||||
	}}
 | 
			
		||||
	})
 | 
			
		||||
	var err error
 | 
			
		||||
	newServiceId, err = CreateService(s)
 | 
			
		||||
	newServiceId, err = s.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotZero(t, newServiceId)
 | 
			
		||||
	newService := SelectService(newServiceId)
 | 
			
		||||
| 
						 | 
				
			
			@ -195,16 +195,16 @@ func TestServiceFailedCheck(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateFailingTCPService(t *testing.T) {
 | 
			
		||||
	s := &Service{Service: &types.Service{
 | 
			
		||||
	s := ReturnService(&types.Service{
 | 
			
		||||
		Name:     "Bad TCP",
 | 
			
		||||
		Domain:   "localhost",
 | 
			
		||||
		Port:     5050,
 | 
			
		||||
		Interval: 30,
 | 
			
		||||
		Type:     "tcp",
 | 
			
		||||
		Timeout:  5,
 | 
			
		||||
	}}
 | 
			
		||||
	})
 | 
			
		||||
	var err error
 | 
			
		||||
	newServiceId, err = CreateService(s)
 | 
			
		||||
	newServiceId, err = s.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotZero(t, newServiceId)
 | 
			
		||||
	newService := SelectService(newServiceId)
 | 
			
		||||
| 
						 | 
				
			
			@ -219,13 +219,12 @@ func TestServiceFailedTCPCheck(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateServiceFailure(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	fail := FailureData{
 | 
			
		||||
		Issue: "This is not an issue, but it would container HTTP response errors.",
 | 
			
		||||
	fail := &types.Failure{
 | 
			
		||||
		Issue:  "This is not an issue, but it would container HTTP response errors.",
 | 
			
		||||
		Method: "http",
 | 
			
		||||
	}
 | 
			
		||||
	service := SelectService(8)
 | 
			
		||||
 | 
			
		||||
	id, err := CreateServiceFailure(service, fail)
 | 
			
		||||
	id, err := service.CreateFailure(fail)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotZero(t, id)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -233,34 +232,33 @@ func TestCreateServiceFailure(t *testing.T) {
 | 
			
		|||
func TestDeleteService(t *testing.T) {
 | 
			
		||||
	service := SelectService(newServiceId)
 | 
			
		||||
 | 
			
		||||
	count, err := SelectAllServices()
 | 
			
		||||
	count, err := CoreApp.SelectAllServices()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 8, len(count))
 | 
			
		||||
 | 
			
		||||
	err = DeleteService(service)
 | 
			
		||||
	err = service.Delete()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
 | 
			
		||||
	count, err = SelectAllServices()
 | 
			
		||||
	count, err = CoreApp.SelectAllServices()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, 7, len(count))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestServiceCloseRoutine(t *testing.T) {
 | 
			
		||||
	s := new(types.Service)
 | 
			
		||||
	s := ReturnService(new(types.Service))
 | 
			
		||||
	s.Name = "example"
 | 
			
		||||
	s.Domain = "https://google.com"
 | 
			
		||||
	s.Type = "http"
 | 
			
		||||
	s.Method = "GET"
 | 
			
		||||
	s.ExpectedStatus = 200
 | 
			
		||||
	s.Interval = 1
 | 
			
		||||
	service := NewService(s)
 | 
			
		||||
	service.Start()
 | 
			
		||||
	assert.True(t, service.IsRunning())
 | 
			
		||||
	go CheckQueue(service, false)
 | 
			
		||||
	s.Start()
 | 
			
		||||
	assert.True(t, s.IsRunning())
 | 
			
		||||
	go s.CheckQueue(false)
 | 
			
		||||
	time.Sleep(5 * time.Second)
 | 
			
		||||
	assert.True(t, service.IsRunning())
 | 
			
		||||
	service.Close()
 | 
			
		||||
	assert.False(t, service.IsRunning())
 | 
			
		||||
	service.Close()
 | 
			
		||||
	assert.False(t, service.IsRunning())
 | 
			
		||||
	assert.True(t, s.IsRunning())
 | 
			
		||||
	s.Close()
 | 
			
		||||
	assert.False(t, s.IsRunning())
 | 
			
		||||
	s.Close()
 | 
			
		||||
	assert.False(t, s.IsRunning())
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,7 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
func DeleteConfig() {
 | 
			
		||||
	err := os.Remove("./config.yml")
 | 
			
		||||
	err := os.Remove(utils.Directory + "/config.yml")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ type ErrorResponse struct {
 | 
			
		|||
 | 
			
		||||
func LoadSampleData() error {
 | 
			
		||||
	utils.Log(1, "Inserting Sample Data...")
 | 
			
		||||
	s1 := &Service{Service: &types.Service{
 | 
			
		||||
	s1 := ReturnService(&types.Service{
 | 
			
		||||
		Name:           "Google",
 | 
			
		||||
		Domain:         "https://google.com",
 | 
			
		||||
		ExpectedStatus: 200,
 | 
			
		||||
| 
						 | 
				
			
			@ -43,8 +43,8 @@ func LoadSampleData() error {
 | 
			
		|||
		Type:           "http",
 | 
			
		||||
		Method:         "GET",
 | 
			
		||||
		Timeout:        10,
 | 
			
		||||
	}}
 | 
			
		||||
	s2 := &Service{Service: &types.Service{
 | 
			
		||||
	})
 | 
			
		||||
	s2 := ReturnService(&types.Service{
 | 
			
		||||
		Name:           "Statup Github",
 | 
			
		||||
		Domain:         "https://github.com/hunterlong/statup",
 | 
			
		||||
		ExpectedStatus: 200,
 | 
			
		||||
| 
						 | 
				
			
			@ -52,8 +52,8 @@ func LoadSampleData() error {
 | 
			
		|||
		Type:           "http",
 | 
			
		||||
		Method:         "GET",
 | 
			
		||||
		Timeout:        20,
 | 
			
		||||
	}}
 | 
			
		||||
	s3 := &Service{Service: &types.Service{
 | 
			
		||||
	})
 | 
			
		||||
	s3 := ReturnService(&types.Service{
 | 
			
		||||
		Name:           "JSON Users Test",
 | 
			
		||||
		Domain:         "https://jsonplaceholder.typicode.com/users",
 | 
			
		||||
		ExpectedStatus: 200,
 | 
			
		||||
| 
						 | 
				
			
			@ -61,8 +61,8 @@ func LoadSampleData() error {
 | 
			
		|||
		Type:           "http",
 | 
			
		||||
		Method:         "GET",
 | 
			
		||||
		Timeout:        30,
 | 
			
		||||
	}}
 | 
			
		||||
	s4 := &Service{Service: &types.Service{
 | 
			
		||||
	})
 | 
			
		||||
	s4 := ReturnService(&types.Service{
 | 
			
		||||
		Name:           "JSON API Tester",
 | 
			
		||||
		Domain:         "https://jsonplaceholder.typicode.com/posts",
 | 
			
		||||
		ExpectedStatus: 201,
 | 
			
		||||
| 
						 | 
				
			
			@ -72,32 +72,32 @@ func LoadSampleData() error {
 | 
			
		|||
		Method:         "POST",
 | 
			
		||||
		PostData:       `{ "title": "statup", "body": "bar", "userId": 19999 }`,
 | 
			
		||||
		Timeout:        30,
 | 
			
		||||
	}}
 | 
			
		||||
	s5 := &Service{Service: &types.Service{
 | 
			
		||||
	})
 | 
			
		||||
	s5 := ReturnService(&types.Service{
 | 
			
		||||
		Name:     "Google DNS",
 | 
			
		||||
		Domain:   "8.8.8.8",
 | 
			
		||||
		Interval: 20,
 | 
			
		||||
		Type:     "tcp",
 | 
			
		||||
		Port:     53,
 | 
			
		||||
		Timeout:  120,
 | 
			
		||||
	}}
 | 
			
		||||
	id, err := CreateService(s1)
 | 
			
		||||
	})
 | 
			
		||||
	id, err := s1.Create()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Error creating Service %v: %v", id, err))
 | 
			
		||||
	}
 | 
			
		||||
	id, err = CreateService(s2)
 | 
			
		||||
	id, err = s2.Create()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Error creating Service %v: %v", id, err))
 | 
			
		||||
	}
 | 
			
		||||
	id, err = CreateService(s3)
 | 
			
		||||
	id, err = s3.Create()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Error creating Service %v: %v", id, err))
 | 
			
		||||
	}
 | 
			
		||||
	id, err = CreateService(s4)
 | 
			
		||||
	id, err = s4.Create()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Error creating Service %v: %v", id, err))
 | 
			
		||||
	}
 | 
			
		||||
	id, err = CreateService(s5)
 | 
			
		||||
	id, err = s5.Create()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Error creating TCP Service %v: %v", id, err))
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,38 +23,44 @@ import (
 | 
			
		|||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type User types.User
 | 
			
		||||
type User struct {
 | 
			
		||||
	*types.User
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectUser(id int64) (*types.User, error) {
 | 
			
		||||
	var user *types.User
 | 
			
		||||
func ReturnUser(u *types.User) *User {
 | 
			
		||||
	return &User{User: u}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectUser(id int64) (*User, error) {
 | 
			
		||||
	var user *User
 | 
			
		||||
	col := DbSession.Collection("users")
 | 
			
		||||
	res := col.Find("id", id)
 | 
			
		||||
	err := res.One(&user)
 | 
			
		||||
	return user, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectUsername(username string) (*types.User, error) {
 | 
			
		||||
	var user *types.User
 | 
			
		||||
func SelectUsername(username string) (*User, error) {
 | 
			
		||||
	var user *User
 | 
			
		||||
	col := DbSession.Collection("users")
 | 
			
		||||
	res := col.Find("username", username)
 | 
			
		||||
	err := res.One(&user)
 | 
			
		||||
	return user, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DeleteUser(u *types.User) error {
 | 
			
		||||
func (u *User) Delete() error {
 | 
			
		||||
	col := DbSession.Collection("users")
 | 
			
		||||
	user := col.Find("id", u.Id)
 | 
			
		||||
	return user.Delete()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func UpdateUser(u *types.User) error {
 | 
			
		||||
func (u *User) Update() error {
 | 
			
		||||
	u.CreatedAt = time.Now()
 | 
			
		||||
	col := DbSession.Collection("users")
 | 
			
		||||
	user := col.Find("id", u.Id)
 | 
			
		||||
	return user.Update(u)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CreateUser(u *types.User) (int64, error) {
 | 
			
		||||
func (u *User) Create() (int64, error) {
 | 
			
		||||
	u.CreatedAt = time.Now()
 | 
			
		||||
	u.Password = utils.HashPassword(u.Password)
 | 
			
		||||
	u.ApiKey = utils.NewSHA1Hash(5)
 | 
			
		||||
| 
						 | 
				
			
			@ -71,8 +77,8 @@ func CreateUser(u *types.User) (int64, error) {
 | 
			
		|||
	return uuid.(int64), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SelectAllUsers() ([]User, error) {
 | 
			
		||||
	var users []User
 | 
			
		||||
func SelectAllUsers() ([]*User, error) {
 | 
			
		||||
	var users []*User
 | 
			
		||||
	col := DbSession.Collection("users").Find()
 | 
			
		||||
	err := col.All(&users)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -81,7 +87,7 @@ func SelectAllUsers() ([]User, error) {
 | 
			
		|||
	return users, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func AuthUser(username, password string) (*types.User, bool) {
 | 
			
		||||
func AuthUser(username, password string) (*User, bool) {
 | 
			
		||||
	var auth bool
 | 
			
		||||
	user, err := SelectUsername(username)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,13 +22,13 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
func TestCreateUser(t *testing.T) {
 | 
			
		||||
	user := &types.User{
 | 
			
		||||
	user := ReturnUser(&types.User{
 | 
			
		||||
		Username: "hunter",
 | 
			
		||||
		Password: "password123",
 | 
			
		||||
		Email:    "test@email.com",
 | 
			
		||||
		Admin:    true,
 | 
			
		||||
	}
 | 
			
		||||
	userId, err := CreateUser(user)
 | 
			
		||||
	})
 | 
			
		||||
	userId, err := user.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotZero(t, userId)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -58,7 +58,7 @@ func TestUpdateUser(t *testing.T) {
 | 
			
		|||
	user, err := SelectUser(1)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	user.Username = "updated"
 | 
			
		||||
	err = UpdateUser(user)
 | 
			
		||||
	err = user.Update()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	updatedUser, err := SelectUser(1)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
| 
						 | 
				
			
			@ -66,13 +66,13 @@ func TestUpdateUser(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateUser2(t *testing.T) {
 | 
			
		||||
	user := &types.User{
 | 
			
		||||
	user := ReturnUser(&types.User{
 | 
			
		||||
		Username: "hunterlong",
 | 
			
		||||
		Password: "password123",
 | 
			
		||||
		Email:    "user@email.com",
 | 
			
		||||
		Admin:    true,
 | 
			
		||||
	}
 | 
			
		||||
	userId, err := CreateUser(user)
 | 
			
		||||
	})
 | 
			
		||||
	userId, err := user.Create()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.NotZero(t, userId)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -108,6 +108,6 @@ func TestCheckPassword(t *testing.T) {
 | 
			
		|||
func TestDeleteUser(t *testing.T) {
 | 
			
		||||
	user, err := SelectUser(2)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	err = DeleteUser(user)
 | 
			
		||||
	err = user.Delete()
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
FROM cypress/browsers:chrome67
 | 
			
		||||
MAINTAINER "Hunter Long (https://github.com/hunterlong)"
 | 
			
		||||
# Statup 'test' image for running a full test using the production environment
 | 
			
		||||
 | 
			
		||||
WORKDIR $HOME/statup
 | 
			
		||||
ADD dev/test .
 | 
			
		||||
 | 
			
		||||
RUN npm install node-sass
 | 
			
		||||
ENV SASS=node-sass
 | 
			
		||||
RUN npm install
 | 
			
		||||
 | 
			
		||||
ADD ./statup-linux-amd64 /usr/local/bin/statup
 | 
			
		||||
RUN statup version
 | 
			
		||||
 | 
			
		||||
RUN npm run test-docker
 | 
			
		||||
| 
						 | 
				
			
			@ -1,23 +0,0 @@
 | 
			
		|||
FROM golang:1.10.3-alpine
 | 
			
		||||
MAINTAINER "Hunter Long (https://github.com/hunterlong)"
 | 
			
		||||
# Statup 'test' image for running a full test using the production environment
 | 
			
		||||
 | 
			
		||||
RUN apk add --no-cache libstdc++ gcc g++ make git ca-certificates linux-headers wget curl
 | 
			
		||||
 | 
			
		||||
RUN curl -L -s https://github.com/golang/dep/releases/download/v0.5.0/dep-linux-amd64 -o /go/bin/dep && \
 | 
			
		||||
    chmod +x /go/bin/dep
 | 
			
		||||
 | 
			
		||||
RUN curl -L -s https://assets.statup.io/sass -o /usr/local/bin/sass && \
 | 
			
		||||
    chmod +x /usr/local/bin/sass
 | 
			
		||||
 | 
			
		||||
WORKDIR /go/src/github.com/hunterlong/statup
 | 
			
		||||
ADD . /go/src/github.com/hunterlong/statup
 | 
			
		||||
 | 
			
		||||
ENV VERSION=$(VERSION)
 | 
			
		||||
ENV IS_DOCKER=true
 | 
			
		||||
 | 
			
		||||
RUN make dev-deps
 | 
			
		||||
RUN make install
 | 
			
		||||
 | 
			
		||||
EXPOSE 8080
 | 
			
		||||
ENTRYPOINT make test
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,7 @@
 | 
			
		|||
    "cy:run-video": "cypress run --record --key $CYPRESS_KEY",
 | 
			
		||||
    "cy:run": "cypress run",
 | 
			
		||||
    "test": "bash -c \"./test.sh\"",
 | 
			
		||||
    "test-docker": "bash -c \"./test-docker.sh\"",
 | 
			
		||||
    "testnovid": "cypress run",
 | 
			
		||||
    "open": "cypress open"
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
statup > /dev/null &
 | 
			
		||||
 | 
			
		||||
./node_modules/.bin/start-server-and-test start http://localhost:8080/robots.txt cy:run
 | 
			
		||||
| 
						 | 
				
			
			@ -79,8 +79,7 @@ func ApiServiceUpdateHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	var s *types.Service
 | 
			
		||||
	decoder := json.NewDecoder(r.Body)
 | 
			
		||||
	decoder.Decode(&s)
 | 
			
		||||
	service := serv
 | 
			
		||||
	core.UpdateService(service)
 | 
			
		||||
	serv.Update()
 | 
			
		||||
	json.NewEncoder(w).Encode(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +88,7 @@ func ApiAllServicesHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	services, _ := core.SelectAllServices()
 | 
			
		||||
	services, _ := core.CoreApp.SelectAllServices()
 | 
			
		||||
	json.NewEncoder(w).Encode(services)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,6 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
type dashboard struct {
 | 
			
		||||
	Services        []*core.Service
 | 
			
		||||
	Core            *core.Core
 | 
			
		||||
	CountOnline     int
 | 
			
		||||
	CountServices   int
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +34,7 @@ func DashboardHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		ExecuteResponse(w, r, "login.html", err)
 | 
			
		||||
	} else {
 | 
			
		||||
		fails := core.CountFailures()
 | 
			
		||||
		out := dashboard{core.CoreApp.Services, core.CoreApp, core.CountOnline(), len(core.CoreApp.Services), fails}
 | 
			
		||||
		out := dashboard{core.CoreApp, core.CountOnline(), len(core.CoreApp.Services()), fails}
 | 
			
		||||
		ExecuteResponse(w, r, "dashboard.html", out)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -112,10 +112,22 @@ func ExecuteResponse(w http.ResponseWriter, r *http.Request, file string, data i
 | 
			
		|||
			return utils.UnderScoreString(html)
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	t, _ = t.Parse(nav)
 | 
			
		||||
	t, _ = t.Parse(footer)
 | 
			
		||||
	t.Parse(render)
 | 
			
		||||
	t.Execute(w, data)
 | 
			
		||||
	t, err = t.Parse(nav)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
	}
 | 
			
		||||
	t, err = t.Parse(footer)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
	}
 | 
			
		||||
	_, err = t.Parse(render)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
	}
 | 
			
		||||
	err = t.Execute(w, data)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ExecuteJSResponse(w http.ResponseWriter, r *http.Request, file string, data interface{}) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -142,7 +142,9 @@ func TestServiceChartHandler(t *testing.T) {
 | 
			
		|||
	assert.Equal(t, 200, rr.Code)
 | 
			
		||||
	t.Log(body)
 | 
			
		||||
	assert.Contains(t, body, "var ctx_1")
 | 
			
		||||
	assert.Contains(t, body, "var ctx_2")
 | 
			
		||||
	assert.Contains(t, body, "var ctx_3")
 | 
			
		||||
	assert.Contains(t, body, "var ctx_4")
 | 
			
		||||
	assert.Contains(t, body, "var ctx_5")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDashboardHandler(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,9 +41,9 @@ func PrometheusHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	}
 | 
			
		||||
	metrics := []string{}
 | 
			
		||||
	system := fmt.Sprintf("statup_total_failures %v\n", core.CountFailures())
 | 
			
		||||
	system += fmt.Sprintf("statup_total_services %v", len(core.CoreApp.Services))
 | 
			
		||||
	system += fmt.Sprintf("statup_total_services %v", len(core.CoreApp.DbServices))
 | 
			
		||||
	metrics = append(metrics, system)
 | 
			
		||||
	for _, ser := range core.CoreApp.Services {
 | 
			
		||||
	for _, ser := range core.CoreApp.DbServices {
 | 
			
		||||
		v := ser
 | 
			
		||||
		online := 1
 | 
			
		||||
		if !v.Online {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,6 @@ import (
 | 
			
		|||
	"github.com/hunterlong/statup/source"
 | 
			
		||||
	"github.com/hunterlong/statup/utils"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -89,9 +88,6 @@ func Router() *mux.Router {
 | 
			
		|||
	r.Handle("/api/users", http.HandlerFunc(ApiAllUsersHandler))
 | 
			
		||||
	r.Handle("/api/users/{id}", http.HandlerFunc(ApiUserHandler))
 | 
			
		||||
	r.Handle("/metrics", http.HandlerFunc(PrometheusHandler))
 | 
			
		||||
	if os.Getenv("GO_ENV") == "test" {
 | 
			
		||||
		r.Handle("/reset", http.HandlerFunc(ResetDbHandler))
 | 
			
		||||
	}
 | 
			
		||||
	r.NotFoundHandler = http.HandlerFunc(Error404Handler)
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ type Service struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func RenderServiceChartsHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	services := core.CoreApp.Services
 | 
			
		||||
	services := core.CoreApp.Services()
 | 
			
		||||
	w.Header().Set("Content-Type", "text/javascript")
 | 
			
		||||
	w.Header().Set("Cache-Control", "max-age=60")
 | 
			
		||||
	ExecuteJSResponse(w, r, "charts.js", services)
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ func ServicesHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		http.Redirect(w, r, "/", http.StatusSeeOther)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
 | 
			
		||||
	ExecuteResponse(w, r, "services.html", core.CoreApp.DbServices)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CreateServiceHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
| 
						 | 
				
			
			@ -73,15 +73,15 @@ func CreateServiceHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		PostData:       postData,
 | 
			
		||||
		Timeout:        timeout,
 | 
			
		||||
	}}
 | 
			
		||||
	_, err := core.CreateService(service)
 | 
			
		||||
	_, err := service.Create()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("Error starting %v check routine. %v", service.Name, err))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go core.CheckQueue(service, true)
 | 
			
		||||
	go service.CheckQueue(true)
 | 
			
		||||
	core.OnNewService(service)
 | 
			
		||||
 | 
			
		||||
	ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
 | 
			
		||||
	ExecuteResponse(w, r, "services.html", core.CoreApp.DbServices)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ServicesDeleteHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
| 
						 | 
				
			
			@ -96,8 +96,8 @@ func ServicesDeleteHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		return
 | 
			
		||||
	}
 | 
			
		||||
	service := serv
 | 
			
		||||
	core.DeleteService(service)
 | 
			
		||||
	ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
 | 
			
		||||
	service.Delete()
 | 
			
		||||
	ExecuteResponse(w, r, "services.html", core.CoreApp.DbServices)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ServicesViewHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
| 
						 | 
				
			
			@ -142,10 +142,10 @@ func ServicesUpdateHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		PostData:       postData,
 | 
			
		||||
		Timeout:        timeout,
 | 
			
		||||
	}}
 | 
			
		||||
	service = core.UpdateService(serviceUpdate)
 | 
			
		||||
	core.CoreApp.Services, _ = core.SelectAllServices()
 | 
			
		||||
	serviceUpdate.Update()
 | 
			
		||||
	core.CoreApp.SelectAllServices()
 | 
			
		||||
 | 
			
		||||
	serv = core.SelectService(service.Id)
 | 
			
		||||
	serv = core.SelectService(serviceUpdate.Id)
 | 
			
		||||
	ExecuteResponse(w, r, "service.html", serv)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -158,8 +158,8 @@ func ServicesDeleteFailuresHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	serv := core.SelectService(utils.StringInt(vars["id"]))
 | 
			
		||||
	service := serv
 | 
			
		||||
	core.DeleteFailures(service)
 | 
			
		||||
	core.CoreApp.Services, _ = core.SelectAllServices()
 | 
			
		||||
	ExecuteResponse(w, r, "services.html", core.CoreApp.Services)
 | 
			
		||||
	core.CoreApp.SelectAllServices()
 | 
			
		||||
	ExecuteResponse(w, r, "services.html", core.CoreApp.DbServices)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func CheckinCreateUpdateHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +171,7 @@ func CheckinCreateUpdateHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	interval := utils.StringInt(r.PostForm.Get("interval"))
 | 
			
		||||
	serv := core.SelectService(utils.StringInt(vars["id"]))
 | 
			
		||||
	service := serv
 | 
			
		||||
	checkin := &core.Checkin{
 | 
			
		||||
	checkin := &types.Checkin{
 | 
			
		||||
		Service:  service.Id,
 | 
			
		||||
		Interval: interval,
 | 
			
		||||
		Api:      utils.NewSHA1Hash(18),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,7 @@
 | 
			
		|||
package handlers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/hunterlong/statup/core"
 | 
			
		||||
	"github.com/hunterlong/statup/types"
 | 
			
		||||
	"github.com/hunterlong/statup/utils"
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +27,7 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
func SetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if core.CoreApp.Services != nil {
 | 
			
		||||
	if core.CoreApp.DbServices != nil {
 | 
			
		||||
		http.Redirect(w, r, "/", http.StatusSeeOther)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +56,7 @@ func SetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if core.CoreApp.Services != nil {
 | 
			
		||||
	if core.CoreApp.DbServices != nil {
 | 
			
		||||
		http.Redirect(w, r, "/", http.StatusSeeOther)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -74,7 +75,7 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	domain := r.PostForm.Get("domain")
 | 
			
		||||
	email := r.PostForm.Get("email")
 | 
			
		||||
 | 
			
		||||
	config := &core.DbConfig{DbConfig: &types.DbConfig{
 | 
			
		||||
	config := &core.DbConfig{&types.DbConfig{
 | 
			
		||||
		DbConn:      dbConn,
 | 
			
		||||
		DbHost:      dbHost,
 | 
			
		||||
		DbUser:      dbUser,
 | 
			
		||||
| 
						 | 
				
			
			@ -88,9 +89,11 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		Password:    password,
 | 
			
		||||
		Email:       email,
 | 
			
		||||
		Error:       nil,
 | 
			
		||||
		Location:    ".",
 | 
			
		||||
		Location:    utils.Directory,
 | 
			
		||||
	}}
 | 
			
		||||
 | 
			
		||||
	fmt.Println(config)
 | 
			
		||||
 | 
			
		||||
	err := config.Save()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(4, err)
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +114,7 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = core.DbConnection(core.Configs.Connection, false, ".")
 | 
			
		||||
	err = core.DbConnection(core.Configs.Connection, false, utils.Directory)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
		core.DeleteConfig()
 | 
			
		||||
| 
						 | 
				
			
			@ -120,13 +123,13 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	admin := &types.User{
 | 
			
		||||
	admin := core.ReturnUser(&types.User{
 | 
			
		||||
		Username: config.Username,
 | 
			
		||||
		Password: config.Password,
 | 
			
		||||
		Email:    config.Email,
 | 
			
		||||
		Admin:    true,
 | 
			
		||||
	}
 | 
			
		||||
	core.CreateUser(admin)
 | 
			
		||||
	})
 | 
			
		||||
	admin.Create()
 | 
			
		||||
 | 
			
		||||
	if sample == "on" {
 | 
			
		||||
		core.LoadSampleData()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,7 @@
 | 
			
		|||
package handlers
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
	"github.com/hunterlong/statup/core"
 | 
			
		||||
	"github.com/hunterlong/statup/types"
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +53,12 @@ func UpdateUserHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	r.ParseForm()
 | 
			
		||||
	vars := mux.Vars(r)
 | 
			
		||||
	id, _ := strconv.Atoi(vars["id"])
 | 
			
		||||
	user, _ := core.SelectUser(int64(id))
 | 
			
		||||
	user, err := core.SelectUser(int64(id))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(3, fmt.Sprintf("user error: %v", err))
 | 
			
		||||
		w.WriteHeader(http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user.Username = r.PostForm.Get("username")
 | 
			
		||||
	user.Email = r.PostForm.Get("email")
 | 
			
		||||
| 
						 | 
				
			
			@ -61,7 +67,7 @@ func UpdateUserHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	if password != "##########" {
 | 
			
		||||
		user.Password = utils.HashPassword(password)
 | 
			
		||||
	}
 | 
			
		||||
	core.UpdateUser(user)
 | 
			
		||||
	user.Update()
 | 
			
		||||
	users, _ := core.SelectAllUsers()
 | 
			
		||||
	ExecuteResponse(w, r, "users.html", users)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -77,15 +83,15 @@ func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
	email := r.PostForm.Get("email")
 | 
			
		||||
	admin := r.PostForm.Get("admin")
 | 
			
		||||
 | 
			
		||||
	user := &types.User{
 | 
			
		||||
	user := core.ReturnUser(&types.User{
 | 
			
		||||
		Username: username,
 | 
			
		||||
		Password: password,
 | 
			
		||||
		Email:    email,
 | 
			
		||||
		Admin:    (admin == "on"),
 | 
			
		||||
	}
 | 
			
		||||
	_, err := core.CreateUser(user)
 | 
			
		||||
	})
 | 
			
		||||
	_, err := user.Create()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		utils.Log(2, err)
 | 
			
		||||
		utils.Log(3, err)
 | 
			
		||||
	}
 | 
			
		||||
	core.OnNewUser(user)
 | 
			
		||||
	http.Redirect(w, r, "/users", http.StatusSeeOther)
 | 
			
		||||
| 
						 | 
				
			
			@ -106,6 +112,6 @@ func UsersDeleteHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		|||
		http.Redirect(w, r, "/users", http.StatusSeeOther)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	core.DeleteUser(user)
 | 
			
		||||
	user.Delete()
 | 
			
		||||
	http.Redirect(w, r, "/users", http.StatusSeeOther)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,14 +20,13 @@ import (
 | 
			
		|||
	"github.com/hunterlong/statup/utils"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
	"os"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"upper.io/db.v3/sqlite"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	testNotifier *Tester
 | 
			
		||||
	testDatabase string
 | 
			
		||||
	dir          string
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			@ -63,15 +62,13 @@ func (n *Tester) Test() error {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	testDatabase = os.Getenv("GOPATH")
 | 
			
		||||
	testDatabase += "/src/github.com/hunterlong/statup"
 | 
			
		||||
 | 
			
		||||
	dir = utils.Directory
 | 
			
		||||
	utils.InitLogs()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func injectDatabase() {
 | 
			
		||||
	sqliteDb := sqlite.ConnectionURL{
 | 
			
		||||
		Database: testDatabase + "/statup.db",
 | 
			
		||||
		Database: dir + "/statup.db",
 | 
			
		||||
	}
 | 
			
		||||
	dbSession, _ := sqlite.Open(sqliteDb)
 | 
			
		||||
	Collections = dbSession.Collection("communication")
 | 
			
		||||
| 
						 | 
				
			
			@ -87,11 +84,11 @@ func TestInit(t *testing.T) {
 | 
			
		|||
 | 
			
		||||
func TestAdd(t *testing.T) {
 | 
			
		||||
	testNotifier = &Tester{&Notification{
 | 
			
		||||
		Id:     1,
 | 
			
		||||
		Id:     999999,
 | 
			
		||||
		Method: "tester",
 | 
			
		||||
		Host:   "0.0.0.0",
 | 
			
		||||
		Form: []NotificationForm{{
 | 
			
		||||
			Id:          1,
 | 
			
		||||
			Id:          999999,
 | 
			
		||||
			Type:        "text",
 | 
			
		||||
			Title:       "Incoming Webhook Url",
 | 
			
		||||
			Placeholder: "Insert your Slack webhook URL here.",
 | 
			
		||||
| 
						 | 
				
			
			@ -119,14 +116,14 @@ func TestInsertDatabase(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestSelectNotification(t *testing.T) {
 | 
			
		||||
	notifier, err := SelectNotification(1)
 | 
			
		||||
	notifier, err := SelectNotification(999999)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	assert.Equal(t, "tester", notifier.Method)
 | 
			
		||||
	assert.False(t, notifier.Enabled)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNotification_Update(t *testing.T) {
 | 
			
		||||
	notifier, err := SelectNotification(1)
 | 
			
		||||
	notifier, err := SelectNotification(999999)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	notifier.Method = "updatedName"
 | 
			
		||||
	notifier.Enabled = true
 | 
			
		||||
| 
						 | 
				
			
			@ -139,7 +136,7 @@ func TestNotification_Update(t *testing.T) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func TestNotification_GetValue(t *testing.T) {
 | 
			
		||||
	notifier, err := SelectNotification(1)
 | 
			
		||||
	notifier, err := SelectNotification(999999)
 | 
			
		||||
	assert.Nil(t, err)
 | 
			
		||||
	val := notifier.GetValue("Host")
 | 
			
		||||
	assert.Equal(t, "0.0.0.0", val)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,31 +47,28 @@
 | 
			
		|||
            <h3>Services</h3>
 | 
			
		||||
 | 
			
		||||
            <div class="list-group mb-5 mt-3">
 | 
			
		||||
            {{ range .Services }}
 | 
			
		||||
            {{ $s := . }}
 | 
			
		||||
            {{ range .Core.Services }}
 | 
			
		||||
                <a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
 | 
			
		||||
                    <div class="d-flex w-100 justify-content-between">
 | 
			
		||||
                        <h5 class="mb-1">{{$s.Name}}</h5>
 | 
			
		||||
                    <small>{{if $s.Online}} <span class="badge badge-success">ONLINE</span> {{else}} <span class="badge badge-danger">OFFLINE</span> {{end}}</small>
 | 
			
		||||
                        <h5 class="mb-1">{{.Name}}</h5>
 | 
			
		||||
                    <small>{{if .Online}} <span class="badge badge-success">ONLINE</span> {{else}} <span class="badge badge-danger">OFFLINE</span> {{end}}</small>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <p class="mb-1">{{.SmallText}}</p>
 | 
			
		||||
                </a>
 | 
			
		||||
            {{ end }}
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
        {{ range .Services }}
 | 
			
		||||
        {{ $s := . }}
 | 
			
		||||
        {{ range .Core.Services }}
 | 
			
		||||
                {{ if .LimitedFailures }}
 | 
			
		||||
                    <h4>{{$s.Name}} Failures</h4>
 | 
			
		||||
                    <h4>{{.Name}} Failures</h4>
 | 
			
		||||
                    <div class="list-group mt-3 mb-4">
 | 
			
		||||
                    {{ range .LimitedFailures }}
 | 
			
		||||
                    {{ $f := .ToFailure }}
 | 
			
		||||
                        <a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
 | 
			
		||||
                            <div class="d-flex w-100 justify-content-between">
 | 
			
		||||
                                <h5 class="mb-1">{{.ParseError}}</h5>
 | 
			
		||||
                                <small>Reported {{.Ago}}</small>
 | 
			
		||||
                            </div>
 | 
			
		||||
                            <p class="mb-1">{{$f.Issue}}</p>
 | 
			
		||||
                            <p class="mb-1">{{.Issue}}</p>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    {{ end }}
 | 
			
		||||
                    </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,11 +28,9 @@
 | 
			
		|||
<div class="col-12 full-col-12 mb-5">
 | 
			
		||||
    <div class="list-group online_list">
 | 
			
		||||
    {{ range .Services }}
 | 
			
		||||
        {{ $s := . }}
 | 
			
		||||
 | 
			
		||||
        <a href="#" class="service_li list-group-item list-group-item-action {{if not $s.Online}}bg-danger text-white{{ end }}" data-id="{{$s.Id}}">
 | 
			
		||||
        {{ $s.Name }}
 | 
			
		||||
        {{if $s.Online}}
 | 
			
		||||
        <a href="#" class="service_li list-group-item list-group-item-action {{if not .Online}}bg-danger text-white{{ end }}" data-id="{{.Id}}">
 | 
			
		||||
        {{ .Name }}
 | 
			
		||||
        {{if .Online}}
 | 
			
		||||
            <span class="badge bg-success float-right pulse-glow">ONLINE</span>
 | 
			
		||||
        {{ else }}
 | 
			
		||||
            <span class="badge bg-white text-black-50 float-right pulse">OFFLINE</span>
 | 
			
		||||
| 
						 | 
				
			
			@ -53,13 +51,12 @@
 | 
			
		|||
    </div>
 | 
			
		||||
{{end}}
 | 
			
		||||
        {{ range .Services }}
 | 
			
		||||
        {{ $s := . }}
 | 
			
		||||
            <div class="mt-4" id="service_id_{{$s.Id}}">
 | 
			
		||||
            <div class="mt-4" id="service_id_{{.Id}}">
 | 
			
		||||
                <div class="card">
 | 
			
		||||
                    <div class="card-body">
 | 
			
		||||
                        <div class="col-12">
 | 
			
		||||
                            <h4 class="mt-3"><a href="/service/{{$s.Id}}"{{if not $s.Online}} class="text-danger"{{end}}>{{ $s.Name }}</a>
 | 
			
		||||
                        {{if $s.Online}}
 | 
			
		||||
                            <h4 class="mt-3"><a href="/service/{{.Id}}"{{if not .Online}} class="text-danger"{{end}}>{{ .Name }}</a>
 | 
			
		||||
                        {{if .Online}}
 | 
			
		||||
                            <span class="badge bg-success float-right">ONLINE</span>
 | 
			
		||||
                        {{ else }}
 | 
			
		||||
                            <span class="badge bg-danger float-right pulse">OFFLINE</span>
 | 
			
		||||
| 
						 | 
				
			
			@ -80,22 +77,19 @@
 | 
			
		|||
                            </div>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                    {{ if .LimitedFailures }}
 | 
			
		||||
 | 
			
		||||
                    {{ end }}
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                {{ if .AvgTime }}
 | 
			
		||||
                    <div class="chart-container">
 | 
			
		||||
                        <canvas id="service_{{ $s.Id }}"></canvas>
 | 
			
		||||
                        <canvas id="service_{{ .Id }}"></canvas>
 | 
			
		||||
                    </div>
 | 
			
		||||
                {{ end }}
 | 
			
		||||
                    <div class="row lower_canvas full-col-12 text-white{{if not $s.Online}} bg-danger{{end}}">
 | 
			
		||||
                    <div class="row lower_canvas full-col-12 text-white{{if not .Online}} bg-danger{{end}}">
 | 
			
		||||
                        <div class="col-10 text-truncate">
 | 
			
		||||
                            <span class="d-none d-md-inline">{{.SmallText}}</span>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <div class="col-sm-12 col-md-2">
 | 
			
		||||
                            <a href="/service/{{ $s.Id }}" class="btn {{if $s.Online}}btn-success{{else}}btn-danger{{end}} btn-sm float-right dyn-dark btn-block">View Service</a>
 | 
			
		||||
                            <a href="/service/{{ .Id }}" class="btn {{if .Online}}btn-success{{else}}btn-danger{{end}} btn-sm float-right dyn-dark btn-block">View Service</a>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
{{ $s := . }}<!doctype html>
 | 
			
		||||
<!doctype html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
| 
						 | 
				
			
			@ -13,7 +13,7 @@
 | 
			
		|||
    <script src="/js/Chart.bundle.min.js"></script>
 | 
			
		||||
{{end}}
 | 
			
		||||
 | 
			
		||||
    <title>Statup | {{$s.Name}} Service</title>
 | 
			
		||||
    <title>Statup | {{.Name}} Service</title>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -25,14 +25,14 @@
 | 
			
		|||
 | 
			
		||||
            <div class="col-12 mb-4">
 | 
			
		||||
 | 
			
		||||
            {{if $s.Online }}
 | 
			
		||||
            {{if .Online }}
 | 
			
		||||
                <span class="mt-3 mb-3 text-white d-md-none btn bg-success d-block d-md-none">ONLINE</span>
 | 
			
		||||
            {{ else }}
 | 
			
		||||
                <span class="mt-3 mb-3 text-white d-md-none btn bg-danger d-block d-md-none">OFFLINE</span>
 | 
			
		||||
            {{end}}
 | 
			
		||||
 | 
			
		||||
                        <h4 class="mt-2">{{ $s.Name }}
 | 
			
		||||
                        {{if $s.Online }}
 | 
			
		||||
                        <h4 class="mt-2">{{ .Name }}
 | 
			
		||||
                        {{if .Online }}
 | 
			
		||||
                            <span class="badge bg-success float-right d-none d-md-block">ONLINE</span>
 | 
			
		||||
                        {{ else }}
 | 
			
		||||
                            <span class="badge bg-danger float-right d-none d-md-block">OFFLINE</span>
 | 
			
		||||
| 
						 | 
				
			
			@ -61,13 +61,12 @@
 | 
			
		|||
            {{ if .LimitedFailures }}
 | 
			
		||||
                <div class="list-group mt-3 mb-4">
 | 
			
		||||
                {{ range .LimitedFailures }}
 | 
			
		||||
                {{ $f := .ToFailure }}
 | 
			
		||||
                    <a href="#" class="list-group-item list-group-item-action flex-column align-items-start">
 | 
			
		||||
                        <div class="d-flex w-100 justify-content-between">
 | 
			
		||||
                            <h5 class="mb-1">{{.ParseError}}</h5>
 | 
			
		||||
                            <small>Reported {{.Ago}}</small>
 | 
			
		||||
                        </div>
 | 
			
		||||
                        <p class="mb-1">{{$f.Issue}}</p>
 | 
			
		||||
                        <p class="mb-1">{{.Issue}}</p>
 | 
			
		||||
                    </a>
 | 
			
		||||
                {{ end }}
 | 
			
		||||
                </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -82,71 +81,71 @@
 | 
			
		|||
 | 
			
		||||
            <h3>Edit Service</h3>
 | 
			
		||||
 | 
			
		||||
            <form action="/service/{{$s.Id}}" method="POST">
 | 
			
		||||
            <form action="/service/{{.Id}}" method="POST">
 | 
			
		||||
                <div class="form-group row">
 | 
			
		||||
                    <label for="service_name" class="col-sm-4 col-form-label">Service Name</label>
 | 
			
		||||
                    <div class="col-sm-8">
 | 
			
		||||
                        <input type="text" name="name" class="form-control" id="service_name" value="{{$s.Name}}" placeholder="Name" required spellcheck="false">
 | 
			
		||||
                        <input type="text" name="name" class="form-control" id="service_name" value="{{.Name}}" placeholder="Name" required spellcheck="false">
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group row">
 | 
			
		||||
                    <label for="service_type" class="col-sm-4 col-form-label">Service Check Type</label>
 | 
			
		||||
                    <div class="col-sm-8">
 | 
			
		||||
                        <select name="check_type" class="form-control" id="service_type" value="{{$s.Type}}">
 | 
			
		||||
                            <option value="http" {{if eq $s.Type "http"}}selected{{end}}>HTTP Service</option>
 | 
			
		||||
                            <option value="tcp" {{if eq $s.Type "tcp"}}selected{{end}}>TCP Service</option>
 | 
			
		||||
                        <select name="check_type" class="form-control" id="service_type" value="{{.Type}}">
 | 
			
		||||
                            <option value="http" {{if eq .Type "http"}}selected{{end}}>HTTP Service</option>
 | 
			
		||||
                            <option value="tcp" {{if eq .Type "tcp"}}selected{{end}}>TCP Service</option>
 | 
			
		||||
                        </select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group row">
 | 
			
		||||
                    <label for="service_url" class="col-sm-4 col-form-label">Application Endpoint (URL)</label>
 | 
			
		||||
                    <div class="col-sm-8">
 | 
			
		||||
                        <input type="text" name="domain" class="form-control" id="service_url" value="{{$s.Domain}}" placeholder="https://google.com" required autocapitalize="false" spellcheck="false">
 | 
			
		||||
                        <input type="text" name="domain" class="form-control" id="service_url" value="{{.Domain}}" placeholder="https://google.com" required autocapitalize="false" spellcheck="false">
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group row{{if eq $s.Type "tcp"}} d-none{{end}}">
 | 
			
		||||
                <div class="form-group row{{if eq .Type "tcp"}} d-none{{end}}">
 | 
			
		||||
                    <label for="service_check_type" class="col-sm-4 col-form-label">Service Check Type</label>
 | 
			
		||||
                    <div class="col-sm-8">
 | 
			
		||||
                        <select name="method" class="form-control" id="service_check_type" value="{{$s.Method}}">
 | 
			
		||||
                            <option value="GET" {{if eq $s.Method "GET"}}selected{{end}}>GET</option>
 | 
			
		||||
                            <option value="POST" {{if eq $s.Method "POST"}}selected{{end}}>POST</option>
 | 
			
		||||
                        <select name="method" class="form-control" id="service_check_type" value="{{.Method}}">
 | 
			
		||||
                            <option value="GET" {{if eq .Method "GET"}}selected{{end}}>GET</option>
 | 
			
		||||
                            <option value="POST" {{if eq .Method "POST"}}selected{{end}}>POST</option>
 | 
			
		||||
                        </select>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group row{{if eq $s.Type "tcp"}} d-none{{end}}">
 | 
			
		||||
                <div class="form-group row{{if eq .Type "tcp"}} d-none{{end}}">
 | 
			
		||||
                    <label for="post_data" class="col-sm-4 col-form-label">Optional Post Data (JSON)</label>
 | 
			
		||||
                    <div class="col-sm-8">
 | 
			
		||||
                        <textarea name="post_data" class="form-control" id="post_data" rows="3" autocapitalize="false" spellcheck="false">{{$s.PostData}}</textarea>
 | 
			
		||||
                        <textarea name="post_data" class="form-control" id="post_data" rows="3" autocapitalize="false" spellcheck="false">{{.PostData}}</textarea>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group row{{if eq $s.Type "tcp"}} d-none{{end}}">
 | 
			
		||||
                <div class="form-group row{{if eq .Type "tcp"}} d-none{{end}}">
 | 
			
		||||
                    <label for="service_response" class="col-sm-4 col-form-label">Expected Response (Regex)</label>
 | 
			
		||||
                    <div class="col-sm-8">
 | 
			
		||||
                        <textarea name="expected" class="form-control" id="service_response" rows="3" autocapitalize="false" spellcheck="false">{{$s.Expected}}</textarea>
 | 
			
		||||
                        <textarea name="expected" class="form-control" id="service_response" rows="3" autocapitalize="false" spellcheck="false">{{.Expected}}</textarea>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group row{{if eq $s.Type "tcp"}} d-none{{end}}">
 | 
			
		||||
                <div class="form-group row{{if eq .Type "tcp"}} d-none{{end}}">
 | 
			
		||||
                    <label for="service_response_code" class="col-sm-4 col-form-label">Expected Status Code</label>
 | 
			
		||||
                    <div class="col-sm-8">
 | 
			
		||||
                        <input type="number" name="expected_status" class="form-control" value="{{$s.ExpectedStatus}}" id="service_response_code">
 | 
			
		||||
                        <input type="number" name="expected_status" class="form-control" value="{{.ExpectedStatus}}" id="service_response_code">
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group row{{if eq $s.Type "http"}} d-none{{end}}">
 | 
			
		||||
                <div class="form-group row{{if eq .Type "http"}} d-none{{end}}">
 | 
			
		||||
                    <label for="service_port" class="col-sm-4 col-form-label">TCP Port</label>
 | 
			
		||||
                    <div class="col-sm-8">
 | 
			
		||||
                        <input type="number" name="port" class="form-control" value="{{$s.Port}}" id="service_port" placeholder="8080">
 | 
			
		||||
                        <input type="number" name="port" class="form-control" value="{{.Port}}" id="service_port" placeholder="8080">
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group row">
 | 
			
		||||
                    <label for="service_interval" class="col-sm-4 col-form-label">Check Interval (Seconds)</label>
 | 
			
		||||
                    <div class="col-sm-8">
 | 
			
		||||
                        <input type="number" name="interval" class="form-control" value="{{$s.Interval}}" id="service_interval" required>
 | 
			
		||||
                        <input type="number" name="interval" class="form-control" value="{{.Interval}}" id="service_interval" required>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group row">
 | 
			
		||||
                    <label for="service_timeout" class="col-sm-4 col-form-label">Timeout in Seconds</label>
 | 
			
		||||
                    <div class="col-sm-8">
 | 
			
		||||
                        <input type="number" name="timeout" class="form-control" value="{{$s.Timeout}}" id="service_timeout" min="1" placeholder="30">
 | 
			
		||||
                        <input type="number" name="timeout" class="form-control" value="{{.Timeout}}" id="service_timeout" min="1" placeholder="30">
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="form-group row">
 | 
			
		||||
| 
						 | 
				
			
			@ -154,34 +153,34 @@
 | 
			
		|||
                        <button type="submit" class="btn btn-success btn-block">Update Service</button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="col-6">
 | 
			
		||||
                        <a href="/service/{{ $s.Id }}/delete_failures" class="btn btn-danger btn-block confirm-btn">Delete All Failures</a>
 | 
			
		||||
                        <a href="/service/{{ .Id }}/delete_failures" class="btn btn-danger btn-block confirm-btn">Delete All Failures</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </form>
 | 
			
		||||
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
<div class="col-12 mt-4{{if eq $s.Type "tcp"}} d-none{{end}}">
 | 
			
		||||
<div class="col-12 mt-4{{if eq .Type "tcp"}} d-none{{end}}">
 | 
			
		||||
    <h3>Last Response</h3>
 | 
			
		||||
    <textarea rows="8" class="form-control" readonly>{{ $s.LastResponse }}</textarea>
 | 
			
		||||
    <textarea rows="8" class="form-control" readonly>{{ .LastResponse }}</textarea>
 | 
			
		||||
    <div class="form-group row mt-2">
 | 
			
		||||
        <label for="last_status_code" class="col-sm-3 col-form-label">HTTP Status Code</label>
 | 
			
		||||
        <div class="col-sm-2">
 | 
			
		||||
            <input type="text" id="last_status_code" class="form-control" value="{{ $s.LastStatusCode }}" readonly>
 | 
			
		||||
            <input type="text" id="last_status_code" class="form-control" value="{{ .LastStatusCode }}" readonly>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<div class="col-12 mt-4{{if eq $s.Type "tcp"}} d-none{{end}}">
 | 
			
		||||
<div class="col-12 mt-4{{if eq .Type "tcp"}} d-none{{end}}">
 | 
			
		||||
    <h3>Service Checkins</h3>
 | 
			
		||||
{{ range $s.Checkins }}
 | 
			
		||||
{{ range .Checkins }}
 | 
			
		||||
    <h5>Check #{{.Id}} <span class="badge online_badge float-right">Checked in {{.Ago}}</span></h5>
 | 
			
		||||
    <input type="text" class="form-control" value="https://domainhere.com/api/checkin/{{.Api}}">
 | 
			
		||||
{{ end }}
 | 
			
		||||
 | 
			
		||||
    <form action="/service/{{$s.Id}}/checkin" method="POST">
 | 
			
		||||
    <form action="/service/{{.Id}}/checkin" method="POST">
 | 
			
		||||
        <div class="form-group row">
 | 
			
		||||
            <label for="service_name" class="col-sm-4 col-form-label">Check Interval (in seconds)</label>
 | 
			
		||||
            <div class="col-md-6 col-sm-12">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
package types
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type Checkin struct {
 | 
			
		||||
	Id        int       `db:"id,omitempty"`
 | 
			
		||||
	Service   int64     `db:"service"`
 | 
			
		||||
	Interval  int64     `db:"check_interval"`
 | 
			
		||||
	Api       string    `db:"api"`
 | 
			
		||||
	CreatedAt time.Time `db:"created_at"`
 | 
			
		||||
	Hits      int64     `json:"hits"`
 | 
			
		||||
	Last      time.Time `json:"last"`
 | 
			
		||||
	CheckinInterface
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CheckinInterface interface {
 | 
			
		||||
	// Database functions
 | 
			
		||||
	Create() (int64, error)
 | 
			
		||||
	//Update() error
 | 
			
		||||
	//Delete() error
 | 
			
		||||
	Ago() string
 | 
			
		||||
	Receivehit()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
package types
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type Core struct {
 | 
			
		||||
	Name           string     `db:"name" json:"name"`
 | 
			
		||||
	Description    string     `db:"description" json:"description"`
 | 
			
		||||
	Config         string     `db:"config" json:"-"`
 | 
			
		||||
	ApiKey         string     `db:"api_key" json:"api_key"`
 | 
			
		||||
	ApiSecret      string     `db:"api_secret" json:"api_secret"`
 | 
			
		||||
	Style          string     `db:"style" json:"-"`
 | 
			
		||||
	Footer         string     `db:"footer" json:"-"`
 | 
			
		||||
	Domain         string     `db:"domain" json:"domain,omitempty"`
 | 
			
		||||
	Version        string     `db:"version" json:"version,omitempty"`
 | 
			
		||||
	MigrationId    int64      `db:"migration_id" json:"-"`
 | 
			
		||||
	UseCdn         bool       `db:"use_cdn" json:"-"`
 | 
			
		||||
	DbServices     []*Service `json:"services,omitempty"`
 | 
			
		||||
	Plugins        []Info
 | 
			
		||||
	Repos          []PluginJSON
 | 
			
		||||
	AllPlugins     []PluginActions
 | 
			
		||||
	Communications []AllNotifiers
 | 
			
		||||
	DbConnection   string
 | 
			
		||||
	Started        time.Time
 | 
			
		||||
	CoreInterface
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CoreInterface interface {
 | 
			
		||||
	SelectAllServices() ([]*Service, error)
 | 
			
		||||
	Services() []*Service
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
package types
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type Failure struct {
 | 
			
		||||
	Id        int       `db:"id,omitempty" json:"id"`
 | 
			
		||||
	Issue     string    `db:"issue" json:"issue"`
 | 
			
		||||
	Method    string    `db:"method" json:"method,omitempty"`
 | 
			
		||||
	Service   int64     `db:"service" json:"service_id"`
 | 
			
		||||
	CreatedAt time.Time `db:"created_at" json:"created_at"`
 | 
			
		||||
	FailureInterface
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FailureInterface interface {
 | 
			
		||||
	Delete() error
 | 
			
		||||
	// method functions
 | 
			
		||||
	Ago() string
 | 
			
		||||
	ParseError() string
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,34 +0,0 @@
 | 
			
		|||
// Statup
 | 
			
		||||
// Copyright (C) 2018.  Hunter Long and the project contributors
 | 
			
		||||
// Written by Hunter Long <info@socialeck.com> and the project contributors
 | 
			
		||||
//
 | 
			
		||||
// https://github.com/hunterlong/statup
 | 
			
		||||
//
 | 
			
		||||
// The licenses for most software and other practical works are designed
 | 
			
		||||
// to take away your freedom to share and change the works.  By contrast,
 | 
			
		||||
// the GNU General Public License is intended to guarantee your freedom to
 | 
			
		||||
// share and change all versions of a program--to make sure it remains free
 | 
			
		||||
// software for all its users.
 | 
			
		||||
//
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
package types
 | 
			
		||||
 | 
			
		||||
type ServiceInterface interface {
 | 
			
		||||
	AvgTime() float64
 | 
			
		||||
	Online24() float32
 | 
			
		||||
	ToService() *Service
 | 
			
		||||
	SmallText() string
 | 
			
		||||
	GraphData() string
 | 
			
		||||
	AvgUptime() string
 | 
			
		||||
	LimitedFailures() []*Failure
 | 
			
		||||
	TotalFailures() (uint64, error)
 | 
			
		||||
	TotalFailures24Hours() (uint64, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FailureInterface interface {
 | 
			
		||||
	ToFailure() *Failure
 | 
			
		||||
	Ago() string
 | 
			
		||||
	ParseError() string
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +46,38 @@ type Service struct {
 | 
			
		|||
	LastStatusCode int
 | 
			
		||||
	LastOnline     time.Time
 | 
			
		||||
	DnsLookup      float64 `json:"dns_lookup_time"`
 | 
			
		||||
	ServiceInterface
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ServiceInterface interface {
 | 
			
		||||
	// Database functions
 | 
			
		||||
	Create() (int64, error)
 | 
			
		||||
	Update() error
 | 
			
		||||
	Delete() error
 | 
			
		||||
	// Basic Method functions
 | 
			
		||||
	AvgTime() float64
 | 
			
		||||
	Online24() float32
 | 
			
		||||
	SmallText() string
 | 
			
		||||
	GraphData() string
 | 
			
		||||
	AvgUptime() string
 | 
			
		||||
	ToJSON() string
 | 
			
		||||
	// Failure functions
 | 
			
		||||
	CreateFailure(*Failure) (int64, error)
 | 
			
		||||
	LimitedFailures() []*Failure
 | 
			
		||||
	AllFailures() []*Failure
 | 
			
		||||
	TotalFailures() (uint64, error)
 | 
			
		||||
	TotalFailures24Hours() (uint64, error)
 | 
			
		||||
	// Hits functions (successful responses)
 | 
			
		||||
	CreateHit(*Hit) (int64, error)
 | 
			
		||||
	Hits() ([]*Hit, error)
 | 
			
		||||
	TotalHits() (uint64, error)
 | 
			
		||||
	Sum() (float64, error)
 | 
			
		||||
	LimitedHits() ([]*Hit, error)
 | 
			
		||||
	SelectHitsGroupBy(string) ([]*Hit, error)
 | 
			
		||||
	// Go Routines
 | 
			
		||||
	CheckQueue(bool)
 | 
			
		||||
	// Checkin functions
 | 
			
		||||
	AllCheckins() []*Checkin
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Service) Start() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,38 +61,6 @@ type PluginActions interface {
 | 
			
		|||
 | 
			
		||||
type AllNotifiers interface{}
 | 
			
		||||
 | 
			
		||||
type Core struct {
 | 
			
		||||
	Name           string     `db:"name" json:"name"`
 | 
			
		||||
	Description    string     `db:"description" json:"description"`
 | 
			
		||||
	Config         string     `db:"config" json:"-"`
 | 
			
		||||
	ApiKey         string     `db:"api_key" json:"api_key"`
 | 
			
		||||
	ApiSecret      string     `db:"api_secret" json:"api_secret"`
 | 
			
		||||
	Style          string     `db:"style" json:"-"`
 | 
			
		||||
	Footer         string     `db:"footer" json:"-"`
 | 
			
		||||
	Domain         string     `db:"domain" json:"domain,omitempty"`
 | 
			
		||||
	Version        string     `db:"version" json:"version,omitempty"`
 | 
			
		||||
	MigrationId    int64      `db:"migration_id" json:"-"`
 | 
			
		||||
	UseCdn         bool       `db:"use_cdn" json:"-"`
 | 
			
		||||
	Services       []*Service `json:"services,omitempty"`
 | 
			
		||||
	Plugins        []Info
 | 
			
		||||
	Repos          []PluginJSON
 | 
			
		||||
	AllPlugins     []PluginActions
 | 
			
		||||
	Communications []AllNotifiers
 | 
			
		||||
	DbConnection   string
 | 
			
		||||
	Started        time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type User struct {
 | 
			
		||||
	Id        int64     `db:"id,omitempty" json:"id"`
 | 
			
		||||
	Username  string    `db:"username" json:"username"`
 | 
			
		||||
	Password  string    `db:"password" json:"-"`
 | 
			
		||||
	Email     string    `db:"email" json:"-"`
 | 
			
		||||
	ApiKey    string    `db:"api_key" json:"api_key"`
 | 
			
		||||
	ApiSecret string    `db:"api_secret" json:"-"`
 | 
			
		||||
	Admin     bool      `db:"administrator" json:"admin"`
 | 
			
		||||
	CreatedAt time.Time `db:"created_at" json:"created_at"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Hit struct {
 | 
			
		||||
	Id        int       `db:"id,omitempty"`
 | 
			
		||||
	Service   int64     `db:"service"`
 | 
			
		||||
| 
						 | 
				
			
			@ -100,24 +68,6 @@ type Hit struct {
 | 
			
		|||
	CreatedAt time.Time `db:"created_at"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Failure struct {
 | 
			
		||||
	Id        int       `db:"id,omitempty" json:"id"`
 | 
			
		||||
	Issue     string    `db:"issue" json:"issue"`
 | 
			
		||||
	Method    string    `db:"method" json:"method,omitempty"`
 | 
			
		||||
	Service   int64     `db:"service" json:"service_id"`
 | 
			
		||||
	CreatedAt time.Time `db:"created_at" json:"created_at"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Checkin struct {
 | 
			
		||||
	Id        int       `db:"id,omitempty"`
 | 
			
		||||
	Service   int64     `db:"service"`
 | 
			
		||||
	Interval  int64     `db:"check_interval"`
 | 
			
		||||
	Api       string    `db:"api"`
 | 
			
		||||
	CreatedAt time.Time `db:"created_at"`
 | 
			
		||||
	Hits      int64     `json:"hits"`
 | 
			
		||||
	Last      time.Time `json:"last"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	Connection string `yaml:"connection"`
 | 
			
		||||
	Host       string `yaml:"host"`
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
package types
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type User struct {
 | 
			
		||||
	Id        int64     `db:"id,omitempty" json:"id"`
 | 
			
		||||
	Username  string    `db:"username" json:"username"`
 | 
			
		||||
	Password  string    `db:"password" json:"-"`
 | 
			
		||||
	Email     string    `db:"email" json:"-"`
 | 
			
		||||
	ApiKey    string    `db:"api_key" json:"api_key"`
 | 
			
		||||
	ApiSecret string    `db:"api_secret" json:"-"`
 | 
			
		||||
	Admin     bool      `db:"administrator" json:"admin"`
 | 
			
		||||
	CreatedAt time.Time `db:"created_at" json:"created_at"`
 | 
			
		||||
	UserInterface
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UserInterface interface {
 | 
			
		||||
	// Database functions
 | 
			
		||||
	Create() (int64, error)
 | 
			
		||||
	Update() error
 | 
			
		||||
	Delete() error
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue