gorm DB - issue fixes - DB seeds - benchmark tests

pull/61/head^2
Hunter Long 2018-09-05 03:54:57 -07:00
parent e4ccdba34d
commit 1eb55a0c71
48 changed files with 1408 additions and 677 deletions

82
Gopkg.lock generated
View File

@ -12,6 +12,14 @@
pruneopts = "UT" pruneopts = "UT"
revision = "c02ca9a983da5807ddf7d796784928f5be4afd09" revision = "c02ca9a983da5807ddf7d796784928f5be4afd09"
[[projects]]
digest = "1:e92f5581902c345eb4ceffdcd4a854fb8f73cf436d47d837d1ec98ef1fe0a214"
name = "github.com/StackExchange/wmi"
packages = ["."]
pruneopts = "UT"
revision = "5d049714c4a64225c3c79a7cf7d02f7fb5b96338"
version = "1.0.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:4b79025e1eaa5726b92e409a46571f1998b56f0a2d881d6271ca616095eae46e" digest = "1:4b79025e1eaa5726b92e409a46571f1998b56f0a2d881d6271ca616095eae46e"
@ -44,6 +52,17 @@
pruneopts = "UT" pruneopts = "UT"
revision = "ebf56d35bba727c68ac77f56f2fcf90b181851aa" revision = "ebf56d35bba727c68ac77f56f2fcf90b181851aa"
[[projects]]
digest = "1:64a5a67c69b70c2420e607a8545d674a23778ed9c3e80607bfd17b77c6c87f6a"
name = "github.com/go-ole/go-ole"
packages = [
".",
"oleutil",
]
pruneopts = "UT"
revision = "a41e3c4b706f6ae8dfbff342b06e40fa4d2d0506"
version = "v1.2.1"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:70a20b8adf085489a342d033b68b7fc27f4017c51e015b857387249493ee0561" digest = "1:70a20b8adf085489a342d033b68b7fc27f4017c51e015b857387249493ee0561"
@ -68,6 +87,14 @@
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42" revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
version = "v1.1.1" version = "v1.1.1"
[[projects]]
digest = "1:664d37ea261f0fc73dd17f4a1f5f46d01fbb0b0d75f6375af064824424109b7d"
name = "github.com/gorilla/handlers"
packages = ["."]
pruneopts = "UT"
revision = "7e0847f9db758cdebd26c149d0ae9d5d0b9c98ce"
version = "v1.4.0"
[[projects]] [[projects]]
digest = "1:195b71563f8432dac9d9692aca2a9ae098bc35763999573eb1c7d52a02a47ce7" digest = "1:195b71563f8432dac9d9692aca2a9ae098bc35763999573eb1c7d52a02a47ce7"
name = "github.com/gorilla/mux" name = "github.com/gorilla/mux"
@ -91,6 +118,14 @@
revision = "03b6f63cc43ef9c7240a635a5e22b13180e822b8" revision = "03b6f63cc43ef9c7240a635a5e22b13180e822b8"
version = "v1.1.1" version = "v1.1.1"
[[projects]]
digest = "1:7b5c6e2eeaa9ae5907c391a91c132abfd5c9e8a784a341b5625e750c67e6825d"
name = "github.com/gorilla/websocket"
packages = ["."]
pruneopts = "UT"
revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d"
version = "v1.4.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:d166a4b3543a71d87e34767ace94e8b516e79ba45111730306f07c8d6f797f1f" digest = "1:d166a4b3543a71d87e34767ace94e8b516e79ba45111730306f07c8d6f797f1f"
@ -126,6 +161,17 @@
pruneopts = "UT" pruneopts = "UT"
revision = "b3511bfdd742af558b54eb6160aca9446d762a19" revision = "b3511bfdd742af558b54eb6160aca9446d762a19"
[[projects]]
branch = "master"
digest = "1:4f4fd75cbdd5ad0696f4d762328f094b9c86061323c9a9f8d0de157f06197e89"
name = "github.com/mkevac/debugcharts"
packages = [
".",
"bindata",
]
pruneopts = "UT"
revision = "d3203a8fa92649b82dc35c214979861de918874a"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:3891cc78541df6e4596b3e73978eb062d32967084069270ec881b959be5155ae" digest = "1:3891cc78541df6e4596b3e73978eb062d32967084069270ec881b959be5155ae"
@ -150,6 +196,29 @@
pruneopts = "UT" pruneopts = "UT"
revision = "6283090d169f51a2410b4e260341a01c9a4c0ca7" revision = "6283090d169f51a2410b4e260341a01c9a4c0ca7"
[[projects]]
digest = "1:7395b855a6078ad2e6c40311402a057a91125fb9f32cf228e1b32cdc57c33538"
name = "github.com/shirou/gopsutil"
packages = [
"cpu",
"host",
"internal/common",
"mem",
"net",
"process",
]
pruneopts = "UT"
revision = "8048a2e9c5773235122027dd585cf821b2af1249"
version = "v2.18.07"
[[projects]]
branch = "master"
digest = "1:99c6a6dab47067c9b898e8c8b13d130c6ab4ffbcc4b7cc6236c2cd0b1e344f5b"
name = "github.com/shirou/w32"
packages = ["."]
pruneopts = "UT"
revision = "bb4de0191aa41b5507caa14b0650cdbddcd9280b"
[[projects]] [[projects]]
digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83" digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83"
name = "github.com/stretchr/testify" name = "github.com/stretchr/testify"
@ -168,6 +237,17 @@
pruneopts = "UT" pruneopts = "UT"
revision = "c126467f60eb25f8f27e5a981f32a87e3965053f" revision = "c126467f60eb25f8f27e5a981f32a87e3965053f"
[[projects]]
branch = "master"
digest = "1:629034aef6b53eb8ea737e6d82cb5402907e2757fbab5ddf5e74c08b4c6473af"
name = "golang.org/x/sys"
packages = [
"unix",
"windows",
]
pruneopts = "UT"
revision = "fa5fdf94c78965f1aa8423f0cc50b8b8d728b05a"
[[projects]] [[projects]]
digest = "1:c25289f43ac4a68d88b02245742347c94f1e108c534dda442188015ff80669b3" digest = "1:c25289f43ac4a68d88b02245742347c94f1e108c534dda442188015ff80669b3"
name = "google.golang.org/appengine" name = "google.golang.org/appengine"
@ -230,9 +310,11 @@
"github.com/ararog/timeago", "github.com/ararog/timeago",
"github.com/fatih/structs", "github.com/fatih/structs",
"github.com/go-yaml/yaml", "github.com/go-yaml/yaml",
"github.com/gorilla/handlers",
"github.com/gorilla/mux", "github.com/gorilla/mux",
"github.com/gorilla/sessions", "github.com/gorilla/sessions",
"github.com/joho/godotenv", "github.com/joho/godotenv",
"github.com/mkevac/debugcharts",
"github.com/pkg/errors", "github.com/pkg/errors",
"github.com/rendon/testcli", "github.com/rendon/testcli",
"github.com/stretchr/testify/assert", "github.com/stretchr/testify/assert",

View File

@ -1,4 +1,4 @@
VERSION=0.52 VERSION=0.53
BINARY_NAME=statup BINARY_NAME=statup
GOPATH:=$(GOPATH) GOPATH:=$(GOPATH)
GOCMD=go GOCMD=go
@ -26,6 +26,10 @@ docker-build-all: docker-build-base docker-dev docker
docker-publish-all: docker-push-base docker-push-dev docker-push-latest docker-publish-all: docker-push-base docker-push-dev docker-push-latest
seed:
rm -f statup.db
cat dev/seed.sql | sqlite3 statup.db
build: compile build: compile
$(GOBUILD) $(BUILDVERSION) -o $(BINARY_NAME) -v ./cmd $(GOBUILD) $(BUILDVERSION) -o $(BINARY_NAME) -v ./cmd

View File

@ -24,13 +24,13 @@ import (
"github.com/hunterlong/statup/source" "github.com/hunterlong/statup/source"
"github.com/hunterlong/statup/types" "github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"github.com/jinzhu/gorm"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"io/ioutil" "io/ioutil"
"math/rand" "math/rand"
"net/http" "net/http"
"strings" "strings"
"time" "time"
"upper.io/db.v3/sqlite"
) )
const ( const (
@ -45,6 +45,8 @@ func CatchCLI(args []string) error {
LoadDotEnvs() LoadDotEnvs()
switch args[0] { switch args[0] {
case "seed":
handlers.DesktopInit(ipAddress, port)
case "app": case "app":
handlers.DesktopInit(ipAddress, port) handlers.DesktopInit(ipAddress, port)
case "version": case "version":
@ -94,7 +96,7 @@ func CatchCLI(args []string) error {
case "export": case "export":
var err error var err error
fmt.Printf("Statup v%v Exporting Static 'index.html' page...\n", VERSION) fmt.Printf("Statup v%v Exporting Static 'index.html' page...\n", VERSION)
core.Configs, err = core.LoadConfig() core.Configs, err = core.LoadConfig(dir)
if err != nil { if err != nil {
utils.Log(4, "config.yml file not found") utils.Log(4, "config.yml file not found")
return err return err
@ -132,11 +134,11 @@ func CatchCLI(args []string) error {
func RunOnce() { func RunOnce() {
var err error var err error
core.Configs, err = core.LoadConfig() core.Configs, err = core.LoadConfig(utils.Directory)
if err != nil { if err != nil {
utils.Log(4, "config.yml file not found") utils.Log(4, "config.yml file not found")
} }
err = core.DbConnection(core.Configs.Connection, false, utils.Directory) err = core.Configs.Connect(false, utils.Directory)
if err != nil { if err != nil {
utils.Log(4, err) utils.Log(4, err)
} }
@ -234,19 +236,16 @@ func FakeSeed(plug types.PluginActions) {
fmt.Printf("\n" + BRAKER) fmt.Printf("\n" + BRAKER)
fmt.Println("\nCreating a SQLite database for testing, will be deleted automatically...") fmt.Println("\nCreating a SQLite database for testing, will be deleted automatically...")
sqlFake := sqlite.ConnectionURL{ core.DbSession, err = gorm.Open("sqlite", "./.plugin_test.db")
Database: "./.plugin_test.db",
}
core.DbSession, err = sqlite.Open(sqlFake)
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
} }
up, _ := source.SqlBox.String("sqlite_up.sql") up, _ := source.SqlBox.String("sqlite_up.sql")
requests := strings.Split(up, ";") requests := strings.Split(up, ";")
for _, request := range requests { for _, request := range requests {
_, err := core.DbSession.Exec(request) db := core.DbSession.Exec(request)
if err != nil { if db.Error != nil {
utils.Log(2, err) utils.Log(2, db.Error)
} }
} }

View File

@ -55,6 +55,8 @@ func parseFlags() {
func main() { func main() {
var err error var err error
parseFlags() parseFlags()
LoadDotEnvs()
source.Assets()
utils.InitLogs() utils.InitLogs()
args := flag.Args() args := flag.Args()
@ -68,13 +70,8 @@ func main() {
os.Exit(1) os.Exit(1)
} }
} }
source.Assets()
LoadDotEnvs()
utils.Log(1, fmt.Sprintf("Starting Statup v%v", VERSION)) utils.Log(1, fmt.Sprintf("Starting Statup v%v", VERSION))
core.Configs, err = core.LoadConfig(utils.Directory)
core.Configs, err = core.LoadConfig()
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
core.SetupMode = true core.SetupMode = true
@ -94,15 +91,18 @@ func LoadDotEnvs() error {
} }
func mainProcess() { func mainProcess() {
dir := utils.Directory
var err error var err error
err = core.DbConnection(core.Configs.Connection, false, utils.Directory) core.Configs, err = core.LoadConfig(dir)
if err != nil {
utils.Log(4, fmt.Sprintf("could not load config.yml %v", err))
}
err = core.Configs.Connect(false, dir)
if err != nil { if err != nil {
utils.Log(4, fmt.Sprintf("could not connect to database: %v", err)) utils.Log(4, fmt.Sprintf("could not connect to database: %v", err))
} }
core.RunDatabaseUpgrades() core.RunDatabaseUpgrades()
core.InitApp() core.InitApp()
if !core.SetupMode { if !core.SetupMode {
LoadPlugins(false) LoadPlugins(false)
fmt.Println(handlers.RunHTTPServer(ipAddress, port)) fmt.Println(handlers.RunHTTPServer(ipAddress, port))
@ -170,7 +170,7 @@ func LoadPlugins(debug bool) {
if debug { if debug {
TestPlugin(plugActions) TestPlugin(plugActions)
} else { } else {
plugActions.OnLoad(core.DbSession) plugActions.OnLoad(*core.DbSession)
core.CoreApp.Plugins = append(core.CoreApp.Plugins, plugActions.GetInfo()) core.CoreApp.Plugins = append(core.CoreApp.Plugins, plugActions.GetInfo())
core.CoreApp.AllPlugins = append(core.CoreApp.AllPlugins, plugActions) core.CoreApp.AllPlugins = append(core.CoreApp.AllPlugins, plugActions)
} }

View File

@ -31,27 +31,30 @@ import (
"os" "os"
"strings" "strings"
"testing" "testing"
"time"
) )
var ( var (
route *mux.Router route *mux.Router
testSession *sessions.Session testSession *sessions.Session
dir string dir string
SERVICE_SINCE, _ = time.Parse(time.RFC3339, "2018-08-30T10:42:08-07:00")
) )
func init() { func init() {
dir = utils.Directory dir = utils.Directory
os.Remove(dir + "/statup.db") }
//os.Remove(gopath+"/cmd/config.yml")
os.RemoveAll(dir + "/cmd/assets") func Clean() {
os.RemoveAll(dir + "/logs") utils.DeleteFile(dir + "/config.yml")
utils.DeleteFile(dir + "/statup.db")
utils.DeleteDirectory(dir + "/assets")
utils.DeleteDirectory(dir + "/logs")
} }
func RunInit(t *testing.T) { func RunInit(t *testing.T) {
source.Assets() source.Assets()
os.Remove(dir + "/statup.db") Clean()
os.Remove(dir + "/cmd/config.yml")
os.Remove(dir + "/cmd/index.html")
route = handlers.Router() route = handlers.Router()
LoadDotEnvs() LoadDotEnvs()
core.CoreApp = core.NewCore() core.CoreApp = core.NewCore()
@ -60,35 +63,56 @@ func RunInit(t *testing.T) {
func TestRunAll(t *testing.T) { func TestRunAll(t *testing.T) {
//t.Parallel() //t.Parallel()
databases := []string{"sqlite", "postgres", "mysql"} databases := []string{"postgres", "sqlite", "mysql"}
if os.Getenv("ONLY_DB") != "" { if os.Getenv("ONLY_DB") != "" {
databases = []string{os.Getenv("ONLY_DB")} databases = []string{os.Getenv("ONLY_DB")}
} }
for _, dbt := range databases { for _, dbt := range databases {
t.Run(dbt+" init", func(t *testing.T) { t.Run(dbt+" init", func(t *testing.T) {
RunInit(t) RunInit(t)
}) })
t.Run(dbt+" load database config", func(t *testing.T) { t.Run(dbt+" Save Config", func(t *testing.T) {
RunMakeDatabaseConfig(t, dbt) RunSaveConfig(t, dbt)
})
t.Run(dbt+" run database migrations", func(t *testing.T) {
RunDatabaseMigrations(t, dbt)
})
t.Run(dbt+" Sample Data", func(t *testing.T) {
RunInsertSampleData(t)
}) })
t.Run(dbt+" Load Configs", func(t *testing.T) { t.Run(dbt+" Load Configs", func(t *testing.T) {
RunLoadConfig(t) RunLoadConfig(t)
t.Log(core.Configs)
})
t.Run(dbt+" Connect to Database", func(t *testing.T) {
err := core.Configs.Connect(false, dir)
assert.Nil(t, err)
})
t.Run(dbt+" Drop Database", func(t *testing.T) {
RunDropDatabase(t)
})
t.Run(dbt+" Connect to Database Again", func(t *testing.T) {
err := core.Configs.Connect(false, dir)
assert.Nil(t, err)
})
t.Run(dbt+" Inserting Database Structure", func(t *testing.T) {
RunCreateSchema(t, dbt)
})
t.Run(dbt+" Inserting Seed Data", func(t *testing.T) {
RunInsertSampleData(t)
})
t.Run(dbt+" Connect to Database Again", func(t *testing.T) {
err := core.Configs.Connect(false, dir)
assert.Nil(t, err)
})
t.Run(dbt+" Run Database Migrations", func(t *testing.T) {
t.SkipNow()
RunDatabaseMigrations(t, dbt)
}) })
t.Run(dbt+" Select Core", func(t *testing.T) { t.Run(dbt+" Select Core", func(t *testing.T) {
RunSelectCoreMYQL(t, dbt) RunSelectCoreMYQL(t, dbt)
t.Log(core.CoreApp)
}) })
t.Run(dbt+" Select Services", func(t *testing.T) { t.Run(dbt+" Select Services", func(t *testing.T) {
RunSelectAllMysqlServices(t) RunSelectAllMysqlServices(t)
}) })
t.Run(dbt+" Select Comms", func(t *testing.T) { t.Run(dbt+" Select Comms", func(t *testing.T) {
t.SkipNow()
RunSelectAllMysqlCommunications(t) RunSelectAllMysqlCommunications(t)
}) })
t.Run(dbt+" Create Users", func(t *testing.T) { t.Run(dbt+" Create Users", func(t *testing.T) {
@ -131,7 +155,7 @@ func TestRunAll(t *testing.T) {
t.Run(dbt+" Create Failing Service", func(t *testing.T) { t.Run(dbt+" Create Failing Service", func(t *testing.T) {
RunBadService_Create(t) RunBadService_Create(t)
}) })
t.Run(dbt+" Check Service", func(t *testing.T) { t.Run(dbt+" Check Bad Service", func(t *testing.T) {
RunBadService_Check(t) RunBadService_Check(t)
}) })
t.Run(dbt+" Select Hits", func(t *testing.T) { t.Run(dbt+" Select Hits", func(t *testing.T) {
@ -183,35 +207,24 @@ func TestRunAll(t *testing.T) {
RunSettingsHandler(t) RunSettingsHandler(t)
}) })
t.Run(dbt+" Cleanup", func(t *testing.T) { t.Run(dbt+" Cleanup", func(t *testing.T) {
//Cleanup(t) core.Configs.Close()
core.DbSession = nil
//Clean()
}) })
//<-done
} }
} }
func Cleanup(t *testing.T) { func RunSaveConfig(t *testing.T, db string) {
core.DbSession.ClearCache() var err error
err := core.DbSession.Close()
assert.Nil(t, err)
}
func RunMakeDatabaseConfig(t *testing.T, db string) {
port := 5432 port := 5432
if db == "mysql" { if db == "mysql" {
port = 3306 port = 3306
} }
core.Configs = &core.DbConfig{DbConfig: &types.DbConfig{
//Project string `yaml:"-"`
//Description string `yaml:"-"`
//Domain string `yaml:"-"`
//Username string `yaml:"-"`
//Password string `yaml:"-"`
//Email string `yaml:"-"`
//Error error `yaml:"-"`
//Location string `yaml:"location"`
config := &core.DbConfig{&types.DbConfig{
DbConn: db, DbConn: db,
DbHost: os.Getenv("DB_HOST"), DbHost: os.Getenv("DB_HOST"),
DbUser: os.Getenv("DB_USER"), DbUser: os.Getenv("DB_USER"),
@ -227,14 +240,19 @@ func RunMakeDatabaseConfig(t *testing.T, db string) {
Error: nil, Error: nil,
Location: dir, Location: dir,
}} }}
err := config.Save() core.Configs, err = core.Configs.Save()
assert.Nil(t, err) assert.Nil(t, err)
}
_, err = core.LoadConfig() func RunCreateSchema(t *testing.T, db string) {
err := core.Configs.Connect(false, dir)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, db, core.Configs.Connection) err = core.Configs.CreateDatabase()
assert.Nil(t, err)
}
err = core.DbConnection(core.Configs.Connection, false, dir) func RunConnectDatabase(t *testing.T) {
err := core.Configs.Connect(false, dir)
assert.Nil(t, err) assert.Nil(t, err)
} }
@ -244,22 +262,32 @@ func RunDatabaseMigrations(t *testing.T, db string) {
} }
func RunInsertSampleData(t *testing.T) { func RunInsertSampleData(t *testing.T) {
err := core.LoadSampleData() _, _, err := core.Configs.SeedDatabase()
assert.Nil(t, err) assert.Nil(t, err)
} }
func RunLoadConfig(t *testing.T) { func RunLoadConfig(t *testing.T) {
var err error var err error
core.Configs, err = core.LoadConfig() core.Configs, err = core.LoadConfig(dir)
t.Log(core.Configs)
assert.Nil(t, err) assert.Nil(t, err)
assert.NotNil(t, core.Configs) assert.NotNil(t, core.Configs)
} }
func RunDropDatabase(t *testing.T) {
err := core.Configs.DropDatabase()
assert.Nil(t, err)
}
func RunSelectCoreMYQL(t *testing.T, db string) { func RunSelectCoreMYQL(t *testing.T, db string) {
var err error var err error
core.CoreApp, err = core.SelectCore() core.CoreApp, err = core.SelectCore()
if err != nil {
t.FailNow()
}
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "Testing "+db, core.CoreApp.Name) t.Log("core: ", core.CoreApp.Core)
assert.Equal(t, "Awesome Status", core.CoreApp.Name)
assert.Equal(t, db, core.CoreApp.DbConnection) assert.Equal(t, db, core.CoreApp.DbConnection)
assert.NotEmpty(t, core.CoreApp.ApiKey) assert.NotEmpty(t, core.CoreApp.ApiKey)
assert.NotEmpty(t, core.CoreApp.ApiSecret) assert.NotEmpty(t, core.CoreApp.ApiSecret)
@ -270,12 +298,12 @@ func RunSelectAllMysqlServices(t *testing.T) {
var err error var err error
services, err := core.CoreApp.SelectAllServices() services, err := core.CoreApp.SelectAllServices()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 5, len(services)) assert.Equal(t, 18, len(services))
} }
func RunSelectAllMysqlCommunications(t *testing.T) { func RunSelectAllMysqlCommunications(t *testing.T) {
var err error var err error
notifiers.Collections = core.DbSession.Collection("communication") notifiers.Collections = core.DbSession.Table("communication").Model(&notifiers.Notification{})
comms := notifiers.Load() comms := notifiers.Load()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 3, len(comms)) assert.Equal(t, 3, len(comms))
@ -284,19 +312,19 @@ func RunSelectAllMysqlCommunications(t *testing.T) {
func RunUser_SelectAll(t *testing.T) { func RunUser_SelectAll(t *testing.T) {
users, err := core.SelectAllUsers() users, err := core.SelectAllUsers()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, len(users)) assert.Equal(t, 3, len(users))
} }
func RunUser_Create(t *testing.T) { func RunUser_Create(t *testing.T) {
user := core.ReturnUser(&types.User{ user := core.ReturnUser(&types.User{
Username: "admin", Username: "hunterlong",
Password: "admin", Password: "password123",
Email: "info@testuser.com", Email: "info@gmail.com",
Admin: true, Admin: true,
}) })
id, err := user.Create() id, err := user.Create()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(1), id) assert.Equal(t, int64(2), id)
user2 := core.ReturnUser(&types.User{ user2 := core.ReturnUser(&types.User{
Username: "superadmin", Username: "superadmin",
Password: "admin", Password: "admin",
@ -305,7 +333,7 @@ func RunUser_Create(t *testing.T) {
}) })
id, err = user2.Create() id, err = user2.Create()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(2), id) assert.Equal(t, int64(3), id)
} }
func RunUser_Update(t *testing.T) { func RunUser_Update(t *testing.T) {
@ -342,7 +370,10 @@ func RunSelectAllServices(t *testing.T) {
var err error var err error
services, err := core.CoreApp.SelectAllServices() services, err := core.CoreApp.SelectAllServices()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 5, len(services)) assert.Equal(t, 18, len(services))
for _, s := range services {
assert.NotEmpty(t, s.CreatedAt)
}
} }
func RunOneService_Check(t *testing.T) { func RunOneService_Check(t *testing.T) {
@ -365,8 +396,7 @@ func RunService_Create(t *testing.T) {
}) })
id, err := service.Create() id, err := service.Create()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(6), id) assert.Equal(t, int64(19), id)
t.Log(service)
} }
func RunService_ToJSON(t *testing.T) { func RunService_ToJSON(t *testing.T) {
@ -379,15 +409,20 @@ func RunService_ToJSON(t *testing.T) {
func RunService_AvgTime(t *testing.T) { func RunService_AvgTime(t *testing.T) {
service := core.SelectService(1) service := core.SelectService(1)
assert.NotNil(t, service) assert.NotNil(t, service)
avg := service.AvgUptime() avg := service.AvgUptime24()
assert.Equal(t, "100", avg) assert.Equal(t, "100", avg)
} }
func RunService_Online24(t *testing.T) { func RunService_Online24(t *testing.T) {
service := core.SelectService(1) service := core.SelectService(1)
assert.NotNil(t, service) assert.NotNil(t, service)
online := service.Online24() online := service.OnlineSince(SERVICE_SINCE)
assert.Equal(t, float32(100), online) assert.Equal(t, float32(80), online)
service = core.SelectService(18)
assert.NotNil(t, service)
online = service.OnlineSince(SERVICE_SINCE)
assert.Equal(t, float32(0), online)
} }
func RunService_GraphData(t *testing.T) { func RunService_GraphData(t *testing.T) {
@ -413,13 +448,13 @@ func RunBadService_Create(t *testing.T) {
}) })
id, err := service.Create() id, err := service.Create()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int64(7), id) assert.Equal(t, int64(20), id)
} }
func RunBadService_Check(t *testing.T) { func RunBadService_Check(t *testing.T) {
service := core.SelectService(7) service := core.SelectService(18)
assert.NotNil(t, service) assert.NotNil(t, service)
assert.Equal(t, "Bad Service", service.Name) assert.Equal(t, "Failing URL", service.Name)
for i := 0; i <= 10; i++ { for i := 0; i <= 10; i++ {
service.Check(true) service.Check(true)
} }
@ -431,9 +466,7 @@ func RunDeleteService(t *testing.T) {
assert.NotNil(t, service) assert.NotNil(t, service)
assert.Equal(t, "JSON API Tester", service.Name) assert.Equal(t, "JSON API Tester", service.Name)
assert.True(t, service.IsRunning()) assert.True(t, service.IsRunning())
t.Log(service.Running)
err := service.Delete() err := service.Delete()
t.Log(service.Running)
assert.False(t, service.IsRunning()) assert.False(t, service.IsRunning())
assert.Nil(t, err) assert.Nil(t, err)
} }
@ -441,14 +474,11 @@ func RunDeleteService(t *testing.T) {
func RunCreateService_Hits(t *testing.T) { func RunCreateService_Hits(t *testing.T) {
services := core.CoreApp.Services() services := core.CoreApp.Services()
assert.NotNil(t, services) assert.NotNil(t, services)
assert.Equal(t, 6, len(services)) assert.Equal(t, 19, len(services))
for i := 0; i <= 15; i++ {
for _, s := range services { for _, s := range services {
var service *core.Service service := s.Check(true)
service = s.Check(true)
assert.NotNil(t, service) assert.NotNil(t, service)
} }
}
} }
func RunService_Hits(t *testing.T) { func RunService_Hits(t *testing.T) {
@ -460,9 +490,9 @@ func RunService_Hits(t *testing.T) {
} }
func RunService_Failures(t *testing.T) { func RunService_Failures(t *testing.T) {
service := core.SelectService(7) service := core.SelectService(18)
assert.NotNil(t, service) assert.NotNil(t, service)
assert.Equal(t, "Bad Service", service.Name) assert.Equal(t, "Failing URL", service.Name)
assert.NotEmpty(t, service.Failures) assert.NotEmpty(t, service.Failures)
} }
@ -479,7 +509,7 @@ func RunIndexHandler(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
route.ServeHTTP(rr, req) route.ServeHTTP(rr, req)
assert.True(t, strings.Contains(rr.Body.String(), "This is a test of Statup.io!")) assert.True(t, strings.Contains(rr.Body.String(), "Awesome"))
assert.True(t, strings.Contains(rr.Body.String(), "footer")) assert.True(t, strings.Contains(rr.Body.String(), "footer"))
} }
@ -499,7 +529,7 @@ func RunPrometheusHandler(t *testing.T) {
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
route.ServeHTTP(rr, req) route.ServeHTTP(rr, req)
t.Log(rr.Body.String()) t.Log(rr.Body.String())
assert.True(t, strings.Contains(rr.Body.String(), "statup_total_services 6")) assert.True(t, strings.Contains(rr.Body.String(), "statup_total_services 19"))
assert.True(t, handlers.IsAuthenticated(req)) assert.True(t, handlers.IsAuthenticated(req))
} }
@ -515,7 +545,7 @@ func RunFailingPrometheusHandler(t *testing.T) {
func RunLoginHandler(t *testing.T) { func RunLoginHandler(t *testing.T) {
form := url.Values{} form := url.Values{}
form.Add("username", "admin") form.Add("username", "admin")
form.Add("password", "admin") form.Add("password", "password123")
req, err := http.NewRequest("POST", "/dashboard", strings.NewReader(form.Encode())) req, err := http.NewRequest("POST", "/dashboard", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
assert.Nil(t, err) assert.Nil(t, err)

View File

@ -210,7 +210,9 @@ func RecordSuccess(s *Service) {
s.Online = true s.Online = true
s.LastOnline = time.Now() s.LastOnline = time.Now()
data := &types.Hit{ data := &types.Hit{
Service: s.Id,
Latency: s.Latency, Latency: s.Latency,
CreatedAt: time.Now(),
} }
utils.Log(1, fmt.Sprintf("Service %v Successful: %0.2f ms", s.Name, data.Latency*1000)) utils.Log(1, fmt.Sprintf("Service %v Successful: %0.2f ms", s.Name, data.Latency*1000))
s.CreateHit(data) s.CreateHit(data)

View File

@ -48,26 +48,25 @@ func FindCheckin(api string) *types.Checkin {
func (s *Service) AllCheckins() []*types.Checkin { func (s *Service) AllCheckins() []*types.Checkin {
var checkins []*types.Checkin var checkins []*types.Checkin
col := DbSession.Collection("checkins").Find("service", s.Id).OrderBy("-id") col := checkinDB().Where("service = ?", s.Id).Order("-id")
col.All(&checkins) col.Scan(&checkins)
s.Checkins = checkins s.Checkins = checkins
return checkins return checkins
} }
func (u *Checkin) Create() (int64, error) { func (u *Checkin) Create() (int64, error) {
u.CreatedAt = time.Now() u.CreatedAt = time.Now()
uuid, err := DbSession.Collection("checkins").Insert(u) row := checkinDB().Create(&u)
if uuid == nil { if row.Error == nil {
utils.Log(2, err) utils.Log(2, row.Error)
return 0, err return 0, row.Error
} }
fmt.Println("new checkin: ", uuid) return u.Id, row.Error
return uuid.(int64), err
} }
func SelectCheckinApi(api string) *Checkin { func SelectCheckinApi(api string) *Checkin {
var checkin *Checkin var checkin *Checkin
DbSession.Collection("checkins").Find("api", api).One(&checkin) checkinDB().Where("api = ?", api).Find(&checkin)
return checkin return checkin
} }

View File

@ -23,29 +23,28 @@ import (
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"io/ioutil" "io/ioutil"
"os" "os"
"time"
) )
func LoadConfig() (*types.Config, error) { func LoadConfig(directory string) (*DbConfig, error) {
var configs *types.DbConfig
if os.Getenv("DB_CONN") != "" { if os.Getenv("DB_CONN") != "" {
utils.Log(1, "DB_CONN environment variable was found, waiting for database...") utils.Log(1, "DB_CONN environment variable was found, waiting for database...")
return LoadUsingEnv() return LoadUsingEnv()
} }
Configs = new(types.Config) file, err := ioutil.ReadFile(directory + "/config.yml")
file, err := ioutil.ReadFile(utils.Directory + "/config.yml")
if err != nil { if err != nil {
return nil, errors.New("config.yml file not found - starting in setup mode") return nil, errors.New("config.yml file not found at " + directory + "/config.yml - starting in setup mode")
} }
err = yaml.Unmarshal(file, &Configs) err = yaml.Unmarshal(file, &configs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
CoreApp.DbConnection = Configs.Connection Configs = &DbConfig{configs}
return Configs, err return Configs, err
} }
func LoadUsingEnv() (*types.Config, error) { func LoadUsingEnv() (*DbConfig, error) {
Configs = new(types.Config) Configs = new(DbConfig)
if os.Getenv("DB_CONN") == "" { if os.Getenv("DB_CONN") == "" {
return nil, errors.New("Missing DB_CONN environment variable") return nil, errors.New("Missing DB_CONN environment variable")
} }
@ -61,12 +60,12 @@ func LoadUsingEnv() (*types.Config, error) {
if os.Getenv("DB_DATABASE") == "" { if os.Getenv("DB_DATABASE") == "" {
return nil, errors.New("Missing DB_DATABASE environment variable") return nil, errors.New("Missing DB_DATABASE environment variable")
} }
Configs.Connection = os.Getenv("DB_CONN") Configs.DbConn = os.Getenv("DB_CONN")
Configs.Host = os.Getenv("DB_HOST") Configs.DbHost = os.Getenv("DB_HOST")
Configs.Port = os.Getenv("DB_PORT") Configs.DbPort = int(utils.StringInt(os.Getenv("DB_PORT")))
Configs.User = os.Getenv("DB_USER") Configs.DbUser = os.Getenv("DB_USER")
Configs.Password = os.Getenv("DB_PASS") Configs.Password = os.Getenv("DB_PASS")
Configs.Database = os.Getenv("DB_DATABASE") Configs.DbData = os.Getenv("DB_DATABASE")
CoreApp.DbConnection = os.Getenv("DB_CONN") CoreApp.DbConnection = os.Getenv("DB_CONN")
CoreApp.Name = os.Getenv("NAME") CoreApp.Name = os.Getenv("NAME")
CoreApp.Domain = os.Getenv("DOMAIN") CoreApp.Domain = os.Getenv("DOMAIN")
@ -89,32 +88,19 @@ func LoadUsingEnv() (*types.Config, error) {
Email: "info@localhost.com", Email: "info@localhost.com",
}} }}
err := DbConnection(dbConfig.DbConn, true, utils.Directory) err := dbConfig.Connect(true, utils.Directory)
if err != nil { if err != nil {
utils.Log(4, err) utils.Log(4, err)
return nil, err return nil, err
} }
exists, err := DbSession.Collection("core").Find().Exists() exists := DbSession.HasTable("core")
if !exists { if !exists {
utils.Log(1, fmt.Sprintf("Core database does not exist, creating now!")) utils.Log(1, fmt.Sprintf("Core database does not exist, creating now!"))
DropDatabase() dbConfig.DropDatabase()
CreateDatabase() dbConfig.CreateDatabase()
CoreApp = &Core{Core: &types.Core{ CoreApp, err = dbConfig.InsertCore()
Name: dbConfig.Project,
Description: dbConfig.Description,
Config: "config.yml",
ApiKey: utils.NewSHA1Hash(9),
ApiSecret: utils.NewSHA1Hash(16),
Domain: dbConfig.Domain,
MigrationId: time.Now().Unix(),
}}
CoreApp.DbConnection = dbConfig.DbConn
err := InsertCore(CoreApp)
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
} }

View File

@ -22,7 +22,6 @@ import (
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"github.com/pkg/errors" "github.com/pkg/errors"
"os" "os"
"sort"
"time" "time"
) )
@ -34,7 +33,7 @@ type Core struct {
} }
var ( var (
Configs *types.Config Configs *DbConfig
CoreApp *Core CoreApp *Core
SetupMode bool SetupMode bool
VERSION string VERSION string
@ -51,12 +50,6 @@ func NewCore() *Core {
return CoreApp return CoreApp
} }
func InsertCore(c *Core) error {
col := DbSession.Collection("core")
_, err := col.Insert(c.Core)
return err
}
func (c *Core) ToCore() *types.Core { func (c *Core) ToCore() *types.Core {
return c.Core return c.Core
} }
@ -72,19 +65,18 @@ func InitApp() {
func InsertNotifierDB() error { func InsertNotifierDB() error {
if DbSession == nil { if DbSession == nil {
err := DbConnection(CoreApp.DbConnection, false, utils.Directory) err := Configs.Connect(false, utils.Directory)
if err != nil { if err != nil {
return errors.New("database connection has not been created") return errors.New("database connection has not been created")
} }
} }
notifiers.Collections = DbSession.Collection("communication") notifiers.Collections = commDB()
return nil return nil
} }
func UpdateCore(c *Core) (*Core, error) { func UpdateCore(c *Core) (*Core, error) {
res := DbSession.Collection("core").Find().Limit(1) db := coreDB().Update(c)
err := res.Update(c.Core) return c, db.Error
return c, err
} }
func (c Core) UsingAssets() bool { func (c Core) UsingAssets() bool {
@ -122,36 +114,33 @@ func (c Core) AllOnline() bool {
} }
func SelectLastMigration() (int64, error) { func SelectLastMigration() (int64, error) {
var c *types.Core
if DbSession == nil { if DbSession == nil {
return 0, errors.New("Database connection has not been created yet") return 0, errors.New("Database connection has not been created yet")
} }
err := DbSession.Collection("core").Find().One(&c) row := coreDB().Take(&CoreApp)
if err != nil { return CoreApp.MigrationId, row.Error
return 0, err
}
return c.MigrationId, err
} }
func SelectCore() (*Core, error) { func SelectCore() (*Core, error) {
var c *types.Core if DbSession == nil {
exists := DbSession.Collection("core").Exists() return nil, errors.New("database has not been initiated yet.")
}
exists := DbSession.HasTable("core")
if !exists { if !exists {
return nil, errors.New("core database has not been setup yet.") return nil, errors.New("core database has not been setup yet.")
} }
err := DbSession.Collection("core").Find().One(&c) db := coreDB().Take(&CoreApp)
if err != nil { if db.Error != nil {
return nil, err return nil, db.Error
} }
CoreApp.Core = c CoreApp.DbConnection = Configs.DbConn
CoreApp.DbConnection = Configs.Connection
CoreApp.Version = VERSION CoreApp.Version = VERSION
CoreApp.SelectAllServices() CoreApp.SelectAllServices()
if os.Getenv("USE_CDN") == "true" { if os.Getenv("USE_CDN") == "true" {
CoreApp.UseCdn = true CoreApp.UseCdn = true
} }
//store = sessions.NewCookieStore([]byte(core.ApiSecret)) //store = sessions.NewCookieStore([]byte(core.ApiSecret))
return CoreApp, err return CoreApp, db.Error
} }
type ServiceOrder []*types.Service type ServiceOrder []*types.Service
@ -163,7 +152,7 @@ func (c ServiceOrder) Less(i, j int) bool { return c[i].Order < c[j].Order }
func (c *Core) Services() []*Service { func (c *Core) Services() []*Service {
var services []*Service var services []*Service
servs := CoreApp.GetServices() servs := CoreApp.GetServices()
sort.Sort(ServiceOrder(servs)) //sort.Sort(ServiceOrder(servs))
for _, ser := range servs { for _, ser := range servs {
services = append(services, ReturnService(ser)) services = append(services, ReturnService(ser))
} }

View File

@ -24,11 +24,13 @@ import (
) )
var ( var (
testCore *Core
testConfig *DbConfig
dir string dir string
) )
const (
SERVICE_SINCE = "2018-08-30T10:42:08-07:00" // "2006-01-02T15:04:05Z07:00"
)
func init() { func init() {
dir = utils.Directory dir = utils.Directory
utils.InitLogs() utils.InitLogs()
@ -36,51 +38,65 @@ func init() {
} }
func TestNewCore(t *testing.T) { func TestNewCore(t *testing.T) {
testCore = NewCore() utils.DeleteFile(dir + "/config.yml")
assert.NotNil(t, testCore) utils.DeleteFile(dir + "/statup.db")
testCore.Name = "Tester" CoreApp = NewCore()
assert.NotNil(t, CoreApp)
CoreApp.Name = "Tester"
} }
func TestDbConfig_Save(t *testing.T) { func TestDbConfig_Save(t *testing.T) {
testConfig = &DbConfig{&types.DbConfig{ var err error
Configs = &DbConfig{&types.DbConfig{
DbConn: "sqlite", DbConn: "sqlite",
Project: "Tester", Project: "Tester",
Location: dir, Location: dir,
}} }}
err := testConfig.Save() Configs, err = Configs.Save()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "sqlite", Configs.DbConn)
assert.NotEmpty(t, Configs.ApiKey)
assert.NotEmpty(t, Configs.ApiSecret)
}
func TestLoadDbConfig(t *testing.T) {
Configs, err := LoadConfig(dir)
assert.Nil(t, err)
assert.Equal(t, "sqlite", Configs.DbConn)
} }
func TestDbConnection(t *testing.T) { func TestDbConnection(t *testing.T) {
err := DbConnection(testConfig.DbConn, false, dir) err := Configs.Connect(false, dir)
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestCreateDatabase(t *testing.T) { func TestSeedSchemaDatabase(t *testing.T) {
err := CreateDatabase() _, _, err := Configs.SeedSchema()
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestInsertCore(t *testing.T) { func TestSeedDatabase(t *testing.T) {
err := InsertCore(testCore) _, _, err := Configs.SeedDatabase()
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestReLoadDbConfig(t *testing.T) {
err := Configs.Connect(false, dir)
assert.Nil(t, err)
assert.Equal(t, "sqlite", Configs.DbConn)
}
func TestSelectCore(t *testing.T) { func TestSelectCore(t *testing.T) {
core, err := SelectCore() core, err := SelectCore()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "Tester", core.Name) assert.Equal(t, "Awesome Status", core.Name)
}
func TestSampleData(t *testing.T) {
err := LoadSampleData()
assert.Nil(t, err)
} }
func TestSelectLastMigration(t *testing.T) { func TestSelectLastMigration(t *testing.T) {
id, err := SelectLastMigration() id, err := SelectLastMigration()
assert.Nil(t, err) assert.Nil(t, err)
assert.NotZero(t, id) //assert.NotZero(t, id)
t.Log("Last migration id: ", id)
} }
func TestInsertNotifierDB(t *testing.T) { func TestInsertNotifierDB(t *testing.T) {

View File

@ -17,94 +17,176 @@ package core
import ( import (
"fmt" "fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/go-yaml/yaml" "github.com/go-yaml/yaml"
"github.com/hunterlong/statup/notifiers"
"github.com/hunterlong/statup/source" "github.com/hunterlong/statup/source"
"github.com/hunterlong/statup/types" "github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mssql"
_ "github.com/jinzhu/gorm/dialects/mysql"
_ "github.com/jinzhu/gorm/dialects/postgres"
_ "github.com/jinzhu/gorm/dialects/sqlite"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
"os" "os"
"strings" "strings"
"time" "time"
"upper.io/db.v3"
"upper.io/db.v3/lib/sqlbuilder"
"upper.io/db.v3/mysql"
"upper.io/db.v3/postgresql"
"upper.io/db.v3/sqlite"
) )
var ( var (
sqliteSettings sqlite.ConnectionURL DbSession *gorm.DB
postgresSettings postgresql.ConnectionURL
mysqlSettings mysql.ConnectionURL
DbSession sqlbuilder.Database
currentMigration int64 currentMigration int64
) )
func failuresDB() *gorm.DB {
if os.Getenv("GO_ENV") == "TEST" {
return DbSession.Model(&types.Failure{}).Debug()
}
return DbSession.Model(&types.Failure{})
}
func (s *Service) allHits() *gorm.DB {
var hits []*Hit
return servicesDB().Find(s).Related(&hits)
}
func hitsDB() *gorm.DB {
if os.Getenv("GO_ENV") == "TEST" {
return DbSession.Model(&types.Hit{}).Debug()
}
return DbSession.Model(&types.Hit{})
}
func servicesDB() *gorm.DB {
if os.Getenv("GO_ENV") == "TEST" {
return DbSession.Model(&types.Service{}).Debug()
}
return DbSession.Model(&types.Service{})
}
func coreDB() *gorm.DB {
if os.Getenv("GO_ENV") == "TEST" {
return DbSession.Table("core").Debug()
}
return DbSession.Table("core")
}
func usersDB() *gorm.DB {
if os.Getenv("GO_ENV") == "TEST" {
return DbSession.Model(&types.User{}).Debug()
}
return DbSession.Model(&types.User{})
}
func commDB() *gorm.DB {
if os.Getenv("GO_ENV") == "TEST" {
return DbSession.Table("communication").Model(&notifiers.Notification{}).Debug()
}
return DbSession.Table("communication").Model(&notifiers.Notification{})
}
func checkinDB() *gorm.DB {
if os.Getenv("GO_ENV") == "TEST" {
return DbSession.Model(&types.Checkin{}).Debug()
}
return DbSession.Model(&types.Checkin{})
}
type DbConfig struct { type DbConfig struct {
*types.DbConfig *types.DbConfig
} }
func DbConnection(dbType string, retry bool, location string) error { func (db *DbConfig) Close() error {
return DbSession.Close()
}
func (db *DbConfig) InsertCore() (*Core, error) {
CoreApp = &Core{Core: &types.Core{
Name: db.Project,
Description: db.Description,
Config: "config.yml",
ApiKey: utils.NewSHA1Hash(9),
ApiSecret: utils.NewSHA1Hash(16),
Domain: db.Domain,
MigrationId: time.Now().Unix(),
}}
CoreApp.DbConnection = db.DbConn
query := coreDB().Create(&CoreApp)
return CoreApp, query.Error
}
func (db *DbConfig) Connect(retry bool, location string) error {
var err error var err error
if dbType == "sqlite" { if DbSession != nil {
sqliteSettings = sqlite.ConnectionURL{ DbSession = nil
Database: location + "/statup.db",
} }
DbSession, err = sqlite.Open(sqliteSettings) switch Configs.DbConn {
case "sqlite":
DbSession, err = gorm.Open("sqlite3", utils.Directory+"/statup.db")
if err != nil { if err != nil {
return err return err
} }
} else if dbType == "mysql" { case "mysql":
if Configs.Port == "" { if Configs.DbPort == 0 {
Configs.Port = "3306" Configs.DbPort = 3306
} }
host := fmt.Sprintf("%v:%v", Configs.Host, Configs.Port) host := fmt.Sprintf("%v:%v", Configs.DbHost, Configs.DbPort)
mysqlSettings = mysql.ConnectionURL{ conn := fmt.Sprintf("%v:%v@tcp(%v)/%v?charset=utf8&parseTime=True&loc=Local", Configs.DbUser, Configs.DbPass, host, Configs.DbData)
Database: Configs.Database, DbSession, err = gorm.Open("mysql", conn)
Host: host, DbSession.DB().SetConnMaxLifetime(time.Minute * 5)
User: Configs.User, DbSession.DB().SetMaxIdleConns(0)
Password: Configs.Password, DbSession.DB().SetMaxOpenConns(5)
Options: map[string]string{"parseTime": "true", "charset": "utf8"},
}
DbSession, err = mysql.Open(mysqlSettings)
if err != nil { if err != nil {
if retry { if retry {
utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host)) utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host))
return waitForDb(dbType) return db.waitForDb()
} else { } else {
return err return err
} }
} }
case "postgres":
if Configs.DbPort == 0 {
Configs.DbPort = 5432
}
conn := fmt.Sprintf("host=%v port=%v user=%v dbname=%v password=%v sslmode=disable", Configs.DbHost, Configs.DbPort, Configs.DbUser, Configs.DbData, Configs.DbPass)
DbSession, err = gorm.Open("postgres", conn)
if err != nil {
if retry {
utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", Configs.DbHost))
return db.waitForDb()
} else { } else {
if Configs.Port == "" { fmt.Println("ERROR:", err)
Configs.Port = "5432" return err
} }
host := fmt.Sprintf("%v:%v", Configs.Host, Configs.Port)
postgresSettings = postgresql.ConnectionURL{
Database: Configs.Database,
Host: host,
User: Configs.User,
Password: Configs.Password,
} }
DbSession, err = postgresql.Open(postgresSettings) case "mssql":
if Configs.DbPort == 0 {
Configs.DbPort = 1433
}
host := fmt.Sprintf("%v:%v", Configs.DbHost, Configs.DbPort)
conn := fmt.Sprintf("sqlserver://%v:%v@%v?database=%v", Configs.DbUser, Configs.DbPass, host, Configs.DbData)
DbSession, err = gorm.Open("mssql", conn)
if err != nil { if err != nil {
if retry { if retry {
utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host)) utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host))
return waitForDb(dbType) return db.waitForDb()
} else { } else {
return err return err
} }
} }
} }
err = DbSession.Ping() err = DbSession.DB().Ping()
if err == nil { if err == nil {
utils.Log(1, fmt.Sprintf("Database connection to '%v' was successful.", DbSession.Name())) utils.Log(1, fmt.Sprintf("Database connection to '%v' was successful.", Configs.DbData))
} }
return err return err
} }
func waitForDb(dbType string) error { func (db *DbConfig) waitForDb() error {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
return DbConnection(dbType, true, utils.Directory) return db.Connect(true, utils.Directory)
} }
func DatabaseMaintence() { func DatabaseMaintence() {
@ -118,9 +200,10 @@ func DatabaseMaintence() {
func DeleteAllSince(table string, date time.Time) { func DeleteAllSince(table string, date time.Time) {
sql := fmt.Sprintf("DELETE FROM %v WHERE created_at < '%v';", table, date.Format("2006-01-02")) sql := fmt.Sprintf("DELETE FROM %v WHERE created_at < '%v';", table, date.Format("2006-01-02"))
_, err := DbSession.Exec(db.Raw(sql)) db := DbSession.Raw(sql)
if err != nil { defer db.Close()
utils.Log(2, err) if db.Error != nil {
utils.Log(2, db.Error)
} }
} }
@ -141,57 +224,44 @@ func (c *DbConfig) Update() error {
return err return err
} }
func (c *DbConfig) Save() error { func (c *DbConfig) Save() (*DbConfig, error) {
var err error var err error
config, err := os.Create(utils.Directory + "/config.yml") config, err := os.Create(utils.Directory + "/config.yml")
if err != nil { if err != nil {
utils.Log(4, err) utils.Log(4, err)
return err return nil, err
} }
c.ApiKey = utils.NewSHA1Hash(16)
c.ApiSecret = utils.NewSHA1Hash(16)
data, err := yaml.Marshal(c.DbConfig) data, err := yaml.Marshal(c.DbConfig)
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
return err return nil, err
} }
config.WriteString(string(data)) config.WriteString(string(data))
config.Close() defer config.Close()
return c, err
Configs, err = LoadConfig() }
if err != nil {
utils.Log(3, err)
return err
}
err = DbConnection(Configs.Connection, false, c.Location)
if err != nil {
utils.Log(4, err)
return err
}
DropDatabase()
CreateDatabase()
func (c *DbConfig) CreateCore() *Core {
newCore := &types.Core{ newCore := &types.Core{
Name: c.Project, Name: c.Project,
Description: c.Description, Description: c.Description,
Config: "config.yml", Config: "config.yml",
ApiKey: utils.NewSHA1Hash(9), ApiKey: c.ApiKey,
ApiSecret: utils.NewSHA1Hash(16), ApiSecret: c.ApiSecret,
Domain: c.Domain, Domain: c.Domain,
MigrationId: time.Now().Unix(), MigrationId: time.Now().Unix(),
} }
col := DbSession.Collection("core") db := coreDB().Create(&newCore)
_, err = col.Insert(newCore) if db.Error == nil {
if err == nil {
CoreApp = &Core{Core: newCore} CoreApp = &Core{Core: newCore}
} }
CoreApp, err := SelectCore()
CoreApp, err = SelectCore()
if err != nil { if err != nil {
utils.Log(4, err) utils.Log(4, err)
} }
CoreApp.DbConnection = c.DbConn return CoreApp
c.ApiKey = CoreApp.ApiKey
c.ApiSecret = CoreApp.ApiSecret
return err
} }
func versionHigher(migrate int64) bool { func versionHigher(migrate int64) bool {
@ -239,10 +309,10 @@ func RunDatabaseUpgrades() error {
continue continue
} }
utils.Log(1, fmt.Sprintf("Running Query: %v", m)) utils.Log(1, fmt.Sprintf("Running Query: %v", m))
_, err := DbSession.Exec(db.Raw(m + ";")) db := DbSession.Raw(m)
ran++ ran++
if err != nil { if db.Error != nil {
utils.Log(2, err) utils.Log(2, db.Error)
continue continue
} }
} }
@ -252,7 +322,7 @@ func RunDatabaseUpgrades() error {
utils.Log(1, fmt.Sprintf("Database Upgraded %v queries ran, current #%v", ran, currentMigration)) utils.Log(1, fmt.Sprintf("Database Upgraded %v queries ran, current #%v", ran, currentMigration))
CoreApp, err = SelectCore() CoreApp, err = SelectCore()
if err != nil { if err != nil {
panic(err) return err
} }
CoreApp.MigrationId = currentMigration CoreApp.MigrationId = currentMigration
UpdateCore(CoreApp) UpdateCore(CoreApp)
@ -260,43 +330,77 @@ func RunDatabaseUpgrades() error {
return err return err
} }
func DropDatabase() error { func (db *DbConfig) SeedSchema() (string, string, error) {
utils.Log(1, "Dropping Database Tables...") utils.Log(1, "Seeding Schema Database with Dummy Data...")
down, err := source.SqlBox.String("down.sql") dir := utils.Directory
var cmd string
switch db.DbConn {
case "sqlite":
cmd = fmt.Sprintf("cat %v/source/sql/sqlite_up.sql | sqlite3 %v/statup.db", dir, dir)
case "mysql":
cmd = fmt.Sprintf("mysql -h %v -P %v -u %v --password=%v %v < %v/source/sql/mysql_up.sql", Configs.DbHost, Configs.DbPort, Configs.DbUser, Configs.DbPass, Configs.DbData, dir)
case "postgres":
cmd = fmt.Sprintf("PGPASSWORD=%v psql -U %v -h %v -d %v -1 -f %v/source/sql/postgres_up.sql", db.DbPass, db.DbUser, db.DbHost, db.DbData, dir)
}
out, outErr, err := utils.Command(cmd)
if err != nil { if err != nil {
return err return out, outErr, err
} }
requests := strings.Split(down, ";") return out, outErr, err
for _, request := range requests {
_, err := DbSession.Exec(request)
if err != nil {
utils.Log(2, err)
}
}
return err
} }
func CreateDatabase() error { func (db *DbConfig) SeedDatabase() (string, string, error) {
utils.Log(1, "Seeding Database with Dummy Data...")
dir := utils.Directory
var cmd string
switch db.DbConn {
case "sqlite":
cmd = fmt.Sprintf("cat %v/dev/sqlite_seed.sql | sqlite3 %v/statup.db", dir, dir)
case "mysql":
cmd = fmt.Sprintf("mysql -h %v -P %v -u %v --password=%v %v < %v/dev/mysql_seed.sql", Configs.DbHost, Configs.DbPort, Configs.DbUser, Configs.DbPass, Configs.DbData, dir)
case "postgres":
cmd = fmt.Sprintf("PGPASSWORD=%v psql -U %v -h %v -d %v -1 -f %v/dev/postgres_seed.sql", db.DbPass, db.DbUser, db.DbHost, db.DbData, dir)
}
out, outErr, err := utils.Command(cmd)
return out, outErr, err
}
func (db *DbConfig) DropDatabase() error {
utils.Log(1, "Dropping Database Tables...")
err := DbSession.DropTableIfExists("checkins")
err = DbSession.DropTableIfExists("communication")
err = DbSession.DropTableIfExists("core")
err = DbSession.DropTableIfExists("failures")
err = DbSession.DropTableIfExists("hits")
err = DbSession.DropTableIfExists("services")
err = DbSession.DropTableIfExists("users")
return err.Error
}
func (db *DbConfig) CreateDatabase() error {
utils.Log(1, "Creating Database Tables...") utils.Log(1, "Creating Database Tables...")
sql := "postgres_up.sql" err := DbSession.CreateTable(&types.Checkin{})
if CoreApp.DbConnection == "mysql" { err = DbSession.Table("communication").CreateTable(&notifiers.Notification{})
sql = "mysql_up.sql" err = DbSession.Table("core").CreateTable(&types.Core{})
} else if CoreApp.DbConnection == "sqlite" { err = DbSession.CreateTable(&types.Failure{})
sql = "sqlite_up.sql" err = DbSession.CreateTable(&types.Hit{})
} err = DbSession.CreateTable(&types.Service{})
up, err := source.SqlBox.String(sql) err = DbSession.CreateTable(&types.User{})
requests := strings.Split(up, ";") utils.Log(1, "Statup Database Created")
for _, request := range requests { return err.Error
_, err := DbSession.Exec(request) }
if err != nil {
utils.Log(2, err) func (db *DbConfig) MigrateDatabase() error {
} utils.Log(1, "Migrating Database Tables...")
} err := DbSession.AutoMigrate(&types.Checkin{})
//secret := NewSHA1Hash() err = DbSession.Table("communication").AutoMigrate(&notifiers.Notification{})
//db.QueryRow("INSERT INTO core (secret, version) VALUES ($1, $2);", secret, VERSION).Scan() err = DbSession.Table("core").AutoMigrate(&types.Core{})
utils.Log(1, "Database Created") err = DbSession.AutoMigrate(&types.Failure{})
//SampleData() err = DbSession.AutoMigrate(&types.Hit{})
return err err = DbSession.AutoMigrate(&types.Service{})
err = DbSession.AutoMigrate(&types.User{})
utils.Log(1, "Statup Database Migrated")
return err.Error
} }
func (c *DbConfig) Clean() *DbConfig { func (c *DbConfig) Clean() *DbConfig {

View File

@ -19,12 +19,12 @@ import (
"github.com/fatih/structs" "github.com/fatih/structs"
"github.com/hunterlong/statup/notifiers" "github.com/hunterlong/statup/notifiers"
"github.com/hunterlong/statup/types" "github.com/hunterlong/statup/types"
"upper.io/db.v3/lib/sqlbuilder" "github.com/jinzhu/gorm"
) )
func OnLoad(db sqlbuilder.Database) { func OnLoad(db *gorm.DB) {
for _, p := range CoreApp.AllPlugins { for _, p := range CoreApp.AllPlugins {
p.OnLoad(db) p.OnLoad(*db)
} }
} }

View File

@ -25,7 +25,11 @@ import (
) )
func injectDatabase() { func injectDatabase() {
DbConnection(Configs.Connection, false, utils.Directory) Configs.Connect(false, utils.Directory)
}
func GenerateSeed() {
} }
func ExportIndexHTML() string { func ExportIndexHTML() string {

View File

@ -32,23 +32,19 @@ func (s *Service) CreateFailure(f *types.Failure) (int64, error) {
f.CreatedAt = time.Now() f.CreatedAt = time.Now()
f.Service = s.Id f.Service = s.Id
s.Failures = append(s.Failures, f) s.Failures = append(s.Failures, f)
col := DbSession.Collection("failures") row := failuresDB().Create(f)
uuid, err := col.Insert(f) if row.Error != nil {
if err != nil { utils.Log(3, row.Error)
utils.Log(3, err) return 0, row.Error
return 0, err
} }
if uuid == nil { return f.Id, row.Error
return 0, err
}
return uuid.(int64), err
} }
func (s *Service) AllFailures() []*types.Failure { func (s *Service) AllFailures() []*types.Failure {
var fails []*types.Failure var fails []*types.Failure
col := DbSession.Collection("failures").Find("service", s.Id).OrderBy("-id") col := failuresDB().Where("service = ?", s.Id).Order("id desc")
err := col.All(&fails) err := col.Find(&fails)
if err != nil { if err.Error != nil {
utils.Log(3, fmt.Sprintf("Issue getting failures for service %v, %v", s.Name, err)) utils.Log(3, fmt.Sprintf("Issue getting failures for service %v, %v", s.Name, err))
return nil return nil
} }
@ -56,8 +52,8 @@ func (s *Service) AllFailures() []*types.Failure {
} }
func (u *Service) DeleteFailures() { func (u *Service) DeleteFailures() {
_, err := DbSession.Exec(`DELETE FROM failures WHERE service = ?`, u.Id) err := DbSession.Exec(`DELETE FROM failures WHERE service = ?`, u.Id)
if err != nil { if err.Error != nil {
utils.Log(3, fmt.Sprintf("failed to delete all failures: %v", err)) utils.Log(3, fmt.Sprintf("failed to delete all failures: %v", err))
} }
u.Failures = nil u.Failures = nil
@ -65,8 +61,8 @@ func (u *Service) DeleteFailures() {
func (s *Service) LimitedFailures() []*Failure { func (s *Service) LimitedFailures() []*Failure {
var failArr []*Failure var failArr []*Failure
col := DbSession.Collection("failures").Find("service", s.Id).OrderBy("-id").Limit(10) col := failuresDB().Where("service = ?", s.Id).Order("id desc").Limit(10)
col.All(&failArr) col.Find(&failArr)
return failArr return failArr
} }
@ -83,30 +79,37 @@ func (f *Failure) Ago() string {
} }
func (f *Failure) Delete() error { func (f *Failure) Delete() error {
col := DbSession.Collection("failures").Find("id", f.Id) db := failuresDB().Delete(f)
return col.Delete() return db.Error
} }
func CountFailures() uint64 { func CountFailures() uint64 {
col := DbSession.Collection("failures").Find() var count uint64
amount, err := col.Count() err := failuresDB().Count(&count)
if err != nil { if err.Error != nil {
utils.Log(2, err) utils.Log(2, err.Error)
return 0 return 0
} }
return amount return count
}
func (s *Service) TotalFailures24() (uint64, error) {
ago := time.Now().Add(-24 * time.Hour)
return s.TotalFailuresSince(ago)
} }
func (s *Service) TotalFailures() (uint64, error) { func (s *Service) TotalFailures() (uint64, error) {
col := DbSession.Collection("failures").Find("service", s.Id) var count uint64
amount, err := col.Count() rows := failuresDB().Where("service = ?", s.Id)
return amount, err err := rows.Count(count)
return count, err.Error
} }
func (s *Service) TotalFailures24Hours() (uint64, error) { func (s *Service) TotalFailuresSince(ago time.Time) (uint64, error) {
col := DbSession.Collection("failures").Find("service", s.Id) var count uint64
amount, err := col.Count() rows := failuresDB().Where("service = ? AND created_at > ?", s.Id, ago.Format("2006-01-02 15:04:05"))
return amount, err err := rows.Count(&count)
return count, err.Error
} }
func (f *Failure) ParseError() string { func (f *Failure) ParseError() string {

View File

@ -19,40 +19,33 @@ import (
"github.com/hunterlong/statup/types" "github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"time" "time"
"upper.io/db.v3"
) )
type Hit struct { type Hit struct {
*types.Hit *types.Hit
} }
func hitCol() db.Collection {
return DbSession.Collection("hits")
}
func (s *Service) CreateHit(h *types.Hit) (int64, error) { func (s *Service) CreateHit(h *types.Hit) (int64, error) {
h.CreatedAt = time.Now() db := hitsDB().Create(&h)
h.Service = s.Id if db.Error != nil {
uuid, err := hitCol().Insert(h) utils.Log(2, db.Error)
if uuid == nil { return 0, db.Error
utils.Log(2, err)
return 0, err
} }
return uuid.(int64), err return h.Id, db.Error
} }
func (s *Service) Hits() ([]*Hit, error) { func (s *Service) Hits() ([]*Hit, error) {
var hits []*Hit var hits []*Hit
col := hitCol().Find("service", s.Id).OrderBy("-id") col := hitsDB().Where("service = ?", s.Id).Order("id desc")
err := col.All(&hits) err := col.Find(&hits)
return hits, err return hits, err.Error
} }
func (s *Service) LimitedHits() ([]*Hit, error) { func (s *Service) LimitedHits() ([]*Hit, error) {
var hits []*Hit var hits []*Hit
col := hitCol().Find("service", s.Id).OrderBy("-id").Limit(1024) col := hitsDB().Where("service = ?", s.Id).Order("id desc").Limit(1024)
err := col.All(&hits) err := col.Find(&hits)
return reverseHits(hits), err return reverseHits(hits), err.Error
} }
func reverseHits(input []*Hit) []*Hit { func reverseHits(input []*Hit) []*Hit {
@ -64,15 +57,27 @@ func reverseHits(input []*Hit) []*Hit {
func (s *Service) SelectHitsGroupBy(group string) ([]*Hit, error) { func (s *Service) SelectHitsGroupBy(group string) ([]*Hit, error) {
var hits []*Hit var hits []*Hit
col := hitCol().Find("service", s.Id) col := hitsDB().Where("service = ?", s.Id)
err := col.All(&hits) err := col.Find(&hits)
return hits, err return hits, err.Error
}
func (s *Service) hits() {
} }
func (s *Service) TotalHits() (uint64, error) { func (s *Service) TotalHits() (uint64, error) {
col := hitCol().Find("service", s.Id) var count uint64
amount, err := col.Count() col := hitsDB().Where("service = ?", s.Id)
return amount, err err := col.Count(&count)
return count, err.Error
}
func (s *Service) TotalHitsSince(ago time.Time) (uint64, error) {
var count uint64
rows := hitsDB().Where("service = ? AND created_at > ?", s.Id, ago.Format("2006-01-02 15:04:05"))
err := rows.Count(&count)
return count, err.Error
} }
func (s *Service) Sum() (float64, error) { func (s *Service) Sum() (float64, error) {

View File

@ -22,7 +22,6 @@ import (
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"strconv" "strconv"
"time" "time"
"upper.io/db.v3"
) )
type Service struct { type Service struct {
@ -30,16 +29,12 @@ type Service struct {
} }
func ReturnService(s *types.Service) *Service { func ReturnService(s *types.Service) *Service {
return &Service{Service: s} return &Service{s}
}
func serviceCol() db.Collection {
return DbSession.Collection("services")
} }
func SelectService(id int64) *Service { func SelectService(id int64) *Service {
for _, s := range CoreApp.Services() { for _, s := range CoreApp.Services() {
if s.Id == id { if s.Service.Id == id {
return s return s
} }
} }
@ -49,11 +44,10 @@ func SelectService(id int64) *Service {
func (c *Core) SelectAllServices() ([]*types.Service, error) { func (c *Core) SelectAllServices() ([]*types.Service, error) {
var services []*types.Service var services []*types.Service
var servs []*types.Service var servs []*types.Service
col := serviceCol().Find().OrderBy("order_id") db := servicesDB().Find(&services)
err := col.All(&services) if db.Error != nil {
if err != nil { utils.Log(3, fmt.Sprintf("service error: %v", db.Error))
utils.Log(3, fmt.Sprintf("service error: %v", err)) return nil, db.Error
return nil, err
} }
for _, ser := range services { for _, ser := range services {
single := ReturnService(ser) single := ReturnService(ser)
@ -63,7 +57,7 @@ func (c *Core) SelectAllServices() ([]*types.Service, error) {
servs = append(servs, single.Service) servs = append(servs, single.Service)
} }
CoreApp.SetServices(servs) CoreApp.SetServices(servs)
return services, err return services, db.Error
} }
func (s *Service) ToJSON() string { func (s *Service) ToJSON() string {
@ -84,12 +78,17 @@ func (s *Service) AvgTime() float64 {
} }
func (s *Service) Online24() float32 { func (s *Service) Online24() float32 {
total, _ := s.TotalHits() ago := time.Now().Add(-24 * time.Hour)
failed, _ := s.TotalFailures24Hours() return s.OnlineSince(ago)
}
func (s *Service) OnlineSince(ago time.Time) float32 {
failed, _ := s.TotalFailuresSince(ago)
if failed == 0 { if failed == 0 {
s.Online24Hours = 100.00 s.Online24Hours = 100.00
return s.Online24Hours return s.Online24Hours
} }
total, _ := s.TotalHitsSince(ago)
if total == 0 { if total == 0 {
s.Online24Hours = 0 s.Online24Hours = 0
return s.Online24Hours return s.Online24Hours
@ -150,16 +149,17 @@ func (s *Service) GraphData() string {
var d []*DateScan var d []*DateScan
since := time.Now().Add(time.Hour*-24 + time.Minute*0 + time.Second*0) since := time.Now().Add(time.Hour*-24 + time.Minute*0 + time.Second*0)
sql := GroupDataBy("hits", s.Id, since, "minute") sql := GroupDataBy("hits", s.Id, since, "minute")
dated, err := DbSession.Query(db.Raw(sql)) rows, err := DbSession.Raw(sql).Rows()
defer rows.Close()
if err != nil { if err != nil {
utils.Log(2, err) utils.Log(2, err)
return "" return ""
} }
for dated.Next() { for rows.Next() {
gd := new(DateScan) gd := new(DateScan)
var tt string var tt string
var ff float64 var ff float64
err := dated.Scan(&tt, &ff) err := rows.Scan(&tt, &ff)
if err != nil { if err != nil {
utils.Log(2, fmt.Sprintf("Issue loading chart data for service %v, %v", s.Name, err)) utils.Log(2, fmt.Sprintf("Issue loading chart data for service %v, %v", s.Name, err))
} }
@ -178,13 +178,18 @@ func (s *Service) GraphData() string {
return string(data) return string(data)
} }
func (s *Service) AvgUptime() string { func (s *Service) AvgUptime24() string {
failed, _ := s.TotalFailures() ago := time.Now().Add(-24 * time.Hour)
total, _ := s.TotalHits() return s.AvgUptime(ago)
}
func (s *Service) AvgUptime(ago time.Time) string {
failed, _ := s.TotalFailuresSince(ago)
if failed == 0 { if failed == 0 {
s.TotalUptime = "100" s.TotalUptime = "100"
return s.TotalUptime return s.TotalUptime
} }
total, _ := s.TotalHitsSince(ago)
if total == 0 { if total == 0 {
s.TotalUptime = "0" s.TotalUptime = "0"
return s.TotalUptime return s.TotalUptime
@ -217,25 +222,27 @@ func updateService(service *Service) {
} }
func (u *Service) Delete() error { func (u *Service) Delete() error {
res := serviceCol().Find("id", u.Id) err := servicesDB().Delete(u)
err := res.Delete() if err.Error != nil {
if err != nil { utils.Log(3, fmt.Sprintf("Failed to delete service %v. %v", u.Name, err.Error))
utils.Log(3, fmt.Sprintf("Failed to delete service %v. %v", u.Name, err)) return err.Error
return err
} }
u.Close() u.Close()
CoreApp.RemoveService(u.index()) CoreApp.RemoveService(u.index())
OnDeletedService(u) OnDeletedService(u)
return err return err.Error
}
func (u *Service) UpdateSingle(attr ...interface{}) error {
return servicesDB().Model(u).Update(attr).Error
} }
func (u *Service) Update(restart bool) error { func (u *Service) Update(restart bool) error {
u.CreatedAt = time.Now() u.CreatedAt = time.Now()
res := serviceCol().Find("id", u.Id) err := servicesDB().Update(u)
err := res.Update(u) if err.Error != nil {
if err != nil {
utils.Log(3, fmt.Sprintf("Failed to update service %v. %v", u.Name, err)) utils.Log(3, fmt.Sprintf("Failed to update service %v. %v", u.Name, err))
return err return err.Error
} }
if restart { if restart {
u.Close() u.Close()
@ -245,20 +252,19 @@ func (u *Service) Update(restart bool) error {
go u.CheckQueue(true) go u.CheckQueue(true)
} }
OnUpdateService(u) OnUpdateService(u)
return err return err.Error
} }
func (u *Service) Create() (int64, error) { func (u *Service) Create() (int64, error) {
u.CreatedAt = time.Now() u.CreatedAt = time.Now()
uuid, err := serviceCol().Insert(u) db := servicesDB().Create(u)
if uuid == nil { if db.Error != nil {
utils.Log(3, fmt.Sprintf("Failed to create service %v. %v", u.Name, err)) utils.Log(3, fmt.Sprintf("Failed to create service %v #%v: %v", u.Name, u.Id, db.Error))
return 0, err return 0, db.Error
} }
u.Id = uuid.(int64)
u.Start() u.Start()
CoreApp.AddService(u.Service) CoreApp.AddService(u.Service)
return uuid.(int64), err return u.Id, nil
} }
func CountOnline() int { func CountOnline() int {

View File

@ -26,23 +26,29 @@ var (
newServiceId int64 newServiceId int64
) )
func TestSelectHTTPService(t *testing.T) {
services, err := CoreApp.SelectAllServices()
assert.Nil(t, err)
assert.Equal(t, 18, len(services))
assert.Equal(t, "Google", services[0].Name)
assert.Equal(t, "http", services[0].Type)
}
func TestSelectAllServices(t *testing.T) { func TestSelectAllServices(t *testing.T) {
services := CoreApp.Services() services := CoreApp.Services()
for _, s := range services { for _, s := range services {
service := s.Check(true) service := s.Check(true)
assert.True(t, service.Online) assert.True(t, service.IsRunning())
t.Logf("ID: %v %v\n", s.Id, s.Name)
} }
assert.Equal(t, 5, len(services)) assert.Equal(t, 18, len(services))
}
func TestSelectHTTPService(t *testing.T) {
service := SelectService(1)
assert.Equal(t, "Google", service.Name)
assert.Equal(t, "http", service.Type)
} }
func TestSelectTCPService(t *testing.T) { func TestSelectTCPService(t *testing.T) {
services := CoreApp.Services()
assert.Equal(t, 18, len(services))
service := SelectService(5) service := SelectService(5)
assert.NotNil(t, service)
assert.Equal(t, "Google DNS", service.Name) assert.Equal(t, "Google DNS", service.Name)
assert.Equal(t, "tcp", service.Type) assert.Equal(t, "tcp", service.Type)
} }
@ -105,9 +111,14 @@ func TestCheckTCPService(t *testing.T) {
} }
func TestServiceOnline24Hours(t *testing.T) { func TestServiceOnline24Hours(t *testing.T) {
service := SelectService(5) since, err := time.Parse(time.RFC3339, SERVICE_SINCE)
amount := service.Online24() assert.Nil(t, err)
assert.Equal(t, float32(100), amount) service := SelectService(1)
assert.Equal(t, float32(83.33), service.OnlineSince(since))
service2 := SelectService(5)
assert.Equal(t, float32(100), service2.OnlineSince(since))
service3 := SelectService(18)
assert.Equal(t, float32(0), service3.OnlineSince(since))
} }
func TestServiceSmallText(t *testing.T) { func TestServiceSmallText(t *testing.T) {
@ -117,30 +128,35 @@ func TestServiceSmallText(t *testing.T) {
} }
func TestServiceAvgUptime(t *testing.T) { func TestServiceAvgUptime(t *testing.T) {
service := SelectService(5) since, err := time.Parse(time.RFC3339, SERVICE_SINCE)
uptime := service.AvgUptime() assert.Nil(t, err)
assert.Equal(t, "100", uptime) service := SelectService(1)
assert.Equal(t, "83.33", service.AvgUptime(since))
service2 := SelectService(5)
assert.Equal(t, "100", service2.AvgUptime(since))
service3 := SelectService(18)
assert.Equal(t, "0.00", service3.AvgUptime(since))
} }
func TestServiceHits(t *testing.T) { func TestServiceHits(t *testing.T) {
service := SelectService(5) service := SelectService(5)
hits, err := service.Hits() hits, err := service.Hits()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int(2), len(hits)) assert.Equal(t, int(5), len(hits))
} }
func TestServiceLimitedHits(t *testing.T) { func TestServiceLimitedHits(t *testing.T) {
service := SelectService(5) service := SelectService(5)
hits, err := service.LimitedHits() hits, err := service.LimitedHits()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, int(2), len(hits)) assert.Equal(t, int(5), len(hits))
} }
func TestServiceTotalHits(t *testing.T) { func TestServiceTotalHits(t *testing.T) {
service := SelectService(5) service := SelectService(5)
hits, err := service.TotalHits() hits, err := service.TotalHits()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, uint64(0x2), hits) assert.Equal(t, uint64(0x5), hits)
} }
func TestServiceSum(t *testing.T) { func TestServiceSum(t *testing.T) {
@ -176,7 +192,6 @@ func TestCreateService(t *testing.T) {
func TestViewNewService(t *testing.T) { func TestViewNewService(t *testing.T) {
newService := SelectService(newServiceId) newService := SelectService(newServiceId)
assert.Equal(t, "That'll do 🐢", newService.Name) assert.Equal(t, "That'll do 🐢", newService.Name)
} }
func TestCreateFailingHTTPService(t *testing.T) { func TestCreateFailingHTTPService(t *testing.T) {
@ -195,10 +210,12 @@ func TestCreateFailingHTTPService(t *testing.T) {
assert.NotZero(t, newServiceId) assert.NotZero(t, newServiceId)
newService := SelectService(newServiceId) newService := SelectService(newServiceId)
assert.Equal(t, "Bad URL", newService.Name) assert.Equal(t, "Bad URL", newService.Name)
t.Log("new service ID: ", newServiceId)
} }
func TestServiceFailedCheck(t *testing.T) { func TestServiceFailedCheck(t *testing.T) {
service := SelectService(7) service := SelectService(20)
assert.Equal(t, "Bad URL", service.Name)
checked := service.Check(true) checked := service.Check(true)
assert.Equal(t, "Bad URL", checked.Name) assert.Equal(t, "Bad URL", checked.Name)
assert.False(t, checked.Online) assert.False(t, checked.Online)
@ -219,10 +236,11 @@ func TestCreateFailingTCPService(t *testing.T) {
assert.NotZero(t, newServiceId) assert.NotZero(t, newServiceId)
newService := SelectService(newServiceId) newService := SelectService(newServiceId)
assert.Equal(t, "Bad TCP", newService.Name) assert.Equal(t, "Bad TCP", newService.Name)
t.Log("new failing tcp service ID: ", newServiceId)
} }
func TestServiceFailedTCPCheck(t *testing.T) { func TestServiceFailedTCPCheck(t *testing.T) {
service := SelectService(8) service := SelectService(21)
checked := service.Check(true) checked := service.Check(true)
assert.Equal(t, "Bad TCP", checked.Name) assert.Equal(t, "Bad TCP", checked.Name)
assert.False(t, checked.Online) assert.False(t, checked.Online)
@ -244,13 +262,13 @@ func TestDeleteService(t *testing.T) {
count, err := CoreApp.SelectAllServices() count, err := CoreApp.SelectAllServices()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 8, len(count)) assert.Equal(t, 21, len(count))
err = service.Delete() err = service.Delete()
assert.Nil(t, err) assert.Nil(t, err)
services := CoreApp.Services() services := CoreApp.Services()
assert.Equal(t, 7, len(services)) assert.Equal(t, 20, len(services))
} }
func TestServiceCloseRoutine(t *testing.T) { func TestServiceCloseRoutine(t *testing.T) {

View File

@ -28,36 +28,29 @@ type User struct {
} }
func ReturnUser(u *types.User) *User { func ReturnUser(u *types.User) *User {
return &User{User: u} return &User{u}
} }
func SelectUser(id int64) (*User, error) { func SelectUser(id int64) (*User, error) {
var user *User var user User
col := DbSession.Collection("users") err := usersDB().First(&user, id)
res := col.Find("id", id) return &user, err.Error
err := res.One(&user)
return user, err
} }
func SelectUsername(username string) (*User, error) { func SelectUsername(username string) (*User, error) {
var user *User var user User
col := DbSession.Collection("users") res := usersDB().Where("username = ?", username)
res := col.Find("username", username) err := res.First(&user)
err := res.One(&user) return &user, err.Error
return user, err
} }
func (u *User) Delete() error { func (u *User) Delete() error {
col := DbSession.Collection("users") return usersDB().Delete(u).Error
user := col.Find("id", u.Id)
return user.Delete()
} }
func (u *User) Update() error { func (u *User) Update() error {
u.CreatedAt = time.Now() u.CreatedAt = time.Now()
col := DbSession.Collection("users") return usersDB().Update(u).Error
user := col.Find("id", u.Id)
return user.Update(u)
} }
func (u *User) Create() (int64, error) { func (u *User) Create() (int64, error) {
@ -65,39 +58,36 @@ func (u *User) Create() (int64, error) {
u.Password = utils.HashPassword(u.Password) u.Password = utils.HashPassword(u.Password)
u.ApiKey = utils.NewSHA1Hash(5) u.ApiKey = utils.NewSHA1Hash(5)
u.ApiSecret = utils.NewSHA1Hash(10) u.ApiSecret = utils.NewSHA1Hash(10)
col := DbSession.Collection("users") db := usersDB().Create(u)
uuid, err := col.Insert(u) if db.Error != nil {
if err != nil { return 0, db.Error
return 0, err
} }
if uuid == nil { if u.Id == 0 {
utils.Log(3, fmt.Sprintf("Failed to create user %v. %v", u.Username, err)) utils.Log(3, fmt.Sprintf("Failed to create user %v. %v", u.Username, db.Error))
return 0, err return 0, db.Error
} }
return uuid.(int64), err return u.Id, db.Error
} }
func SelectAllUsers() ([]*User, error) { func SelectAllUsers() ([]*User, error) {
var users []*User var users []*User
col := DbSession.Collection("users").Find() db := usersDB().Find(&users)
err := col.All(&users) if db.Error != nil {
if err != nil { utils.Log(3, fmt.Sprintf("Failed to load all users. %v", db.Error))
utils.Log(3, fmt.Sprintf("Failed to load all users. %v", err))
} }
return users, err return users, db.Error
} }
func AuthUser(username, password string) (*User, bool) { func AuthUser(username, password string) (*User, bool) {
var auth bool
user, err := SelectUsername(username) user, err := SelectUsername(username)
if err != nil { if err != nil {
utils.Log(2, err) utils.Log(2, err)
return nil, false return nil, false
} }
if CheckHash(password, user.Password) { if CheckHash(password, user.Password) {
auth = true return user, true
} }
return user, auth return nil, false
} }
func CheckHash(password, hash string) bool { func CheckHash(password, hash string) bool {

View File

@ -36,13 +36,13 @@ func TestCreateUser(t *testing.T) {
func TestSelectAllUsers(t *testing.T) { func TestSelectAllUsers(t *testing.T) {
users, err := SelectAllUsers() users, err := SelectAllUsers()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 1, len(users)) assert.Equal(t, 2, len(users))
} }
func TestSelectUser(t *testing.T) { func TestSelectUser(t *testing.T) {
user, err := SelectUser(1) user, err := SelectUser(1)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "test@email.com", user.Email) assert.Equal(t, "info@statup.io", user.Email)
assert.True(t, user.Admin) assert.True(t, user.Admin)
} }
@ -50,7 +50,7 @@ func TestSelectUsername(t *testing.T) {
user, err := SelectUsername("hunter") user, err := SelectUsername("hunter")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "test@email.com", user.Email) assert.Equal(t, "test@email.com", user.Email)
assert.Equal(t, int64(1), user.Id) assert.Equal(t, int64(2), user.Id)
assert.True(t, user.Admin) assert.True(t, user.Admin)
} }
@ -80,7 +80,7 @@ func TestCreateUser2(t *testing.T) {
func TestSelectAllUsersAgain(t *testing.T) { func TestSelectAllUsersAgain(t *testing.T) {
users, err := SelectAllUsers() users, err := SelectAllUsers()
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, 2, len(users)) assert.Equal(t, 3, len(users))
} }
func TestAuthUser(t *testing.T) { func TestAuthUser(t *testing.T) {
@ -88,12 +88,12 @@ func TestAuthUser(t *testing.T) {
assert.True(t, auth) assert.True(t, auth)
assert.NotNil(t, user) assert.NotNil(t, user)
assert.Equal(t, "user@email.com", user.Email) assert.Equal(t, "user@email.com", user.Email)
assert.Equal(t, int64(2), user.Id) assert.Equal(t, int64(3), user.Id)
assert.True(t, user.Admin) assert.True(t, user.Admin)
} }
func TestFailedAuthUser(t *testing.T) { func TestFailedAuthUser(t *testing.T) {
user, auth := AuthUser("hunter", "wrongpassword") user, auth := AuthUser("hunterlong", "wrongpassword")
assert.False(t, auth) assert.False(t, auth)
assert.Nil(t, user) assert.Nil(t, user)
} }
@ -111,3 +111,8 @@ func TestDeleteUser(t *testing.T) {
err = user.Delete() err = user.Delete()
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestDbConfig_Close(t *testing.T) {
err := Configs.Close()
assert.Nil(t, err)
}

142
dev/mysql_seed.sql Normal file
View File

@ -0,0 +1,142 @@
INSERT INTO core (name,description,config,api_key,api_secret,style,footer,domain,version,migration_id,use_cdn) VALUES ('Awesome Status','This is from the seed file!','config.yml','d2fead3e459bd14f570cf08527175b88b32d7faa','e351393306ea245de5f9588cbe8627c74db007c6','','Created by Hunter Long','','',0,false);
INSERT INTO services (name,domain,check_type,method,port,expected,expected_status,check_interval,post_data,order_id,timeout,created_at) VALUES
('Google','https://google.com','http','GET',0,'',200,10,'',0,10,'2018-08-31 10:42:08'),
('Statup Github','https://github.com/hunterlong/statup','http','GET',0,'',200,30,'',0,20,'2018-08-31 10:42:08'),
('JSON Users Test','https://jsonplaceholder.typicode.com/users','http','GET',0,'',200,60,'',0,30,'2018-08-31 10:42:08'),
('JSON API Tester','https://jsonplaceholder.typicode.com/posts','http','POST',0,'(title)": "((\\"|[statup])*)"',201,30,'{ "title": "statup", "body": "bar", "userId": 19999 }',0,30,'2018-08-31 10:42:08'),
('Google DNS','8.8.8.8','tcp','',53,'',0,20,'',0,120,'2018-08-31 10:42:08'),
('The Bravery - An Honest Mistake','https://www.youtube.com/watch?v=O8vzbezVru4','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14'),
('Upper.io','https://upper.io/db.v3/','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14'),
('CoinApp Status','https://status.coinapp.io','http','GET',0,'',200,1,'',0,30,'2018-08-31 10:42:16'),
('Demo Page','https://demo.statup.io','http','GET',0,'',200,2,'',0,30,'2018-08-31 10:42:16'),
('Golang','https://golang.org','http','GET',0,'',200,3,'',0,30,'2018-08-31 10:42:16'),
('Github','https://github.com/hunterlong','http','GET',0,'',200,4,'',0,30,'2018-08-31 10:42:17'),
('Santa Monica','https://www.santamonica.com','http','GET',0,'',200,5,'',0,30,'2018-08-31 10:42:17'),
('Oeschs Die Dritten','https://www.oeschs-die-dritten.ch/en/','http','GET',0,'',200,6,'',0,30,'2018-08-31 10:42:18'),
('EtherScan.io','https://etherscan.io','http','GET',0,'',200,7,'',0,30,'2018-08-31 10:42:20'),
('Test Service 7','https://www.youtube.com/watch?v=ipvEIZMMILA','http','GET',0,'',200,8,'',0,30,'2018-08-31 10:42:20'),
('Test Service 8','https://www.youtube.com/watch?v=UdaYVxYF1Ok','http','GET',0,'',200,9,'',0,30,'2018-08-31 10:42:20'),
('Test Service 9','https://www.youtube.com/watch?v=yydZbVoCbn0&t=870s','http','GET',0,'',200,10,'',0,30,'2018-08-31 10:42:20'),
('Failing URL','http://failingdomainsarenofunatall.com','http','GET',0,'',200,11,'',0,30,'2018-08-31 10:42:20');
INSERT INTO users (username,password,email,api_key,api_secret,administrator,created_at) VALUES
('admin','$2a$14$Aye3yHae0ml6WRtvdgkRnO19OFze0IKF6IOHrdLpETtwLjnPelMUm','info@statup.io','27aa701119fb561d734eb4469cf13ba2550007e2','29de07014d32fbbbb80053ef3c19b464b2b72f64',1,'2018-08-31 10:42:07');
INSERT INTO hits (service,latency,created_at) VALUES
(5,0.006504081,'2018-08-29 10:42:08'),
(3,0.202164333,'2018-08-29 10:42:08'),
(4,0.376675172,'2018-08-29 10:42:09'),
(1,0.413912204,'2018-08-29 10:42:09'),
(1,0.473912204,'2018-08-29 10:42:09'),
(2,0.528427935,'2018-08-29 10:42:09'),
(6,0.11930188,'2018-08-29 10:42:09'),
(7,0.001062722,'2018-08-29 10:42:09'),
(7,0.004046882,'2018-08-29 10:42:09'),
(6,0.063360069,'2018-08-29 10:42:09'),
(8,0.168951416,'2018-08-29 10:42:16'),
(8,0.069032763,'2018-08-29 10:42:16'),
(9,0.47712966,'2018-08-29 10:42:16'),
(10,0.104510482,'2018-08-29 10:42:17'),
(10,0.062536146,'2018-08-29 10:42:17'),
(9,0.352823197,'2018-08-29 10:42:09'),
(8,0.38226374,'2018-08-29 10:42:09'),
(11,0.857324393,'2018-08-29 10:42:17'),
(12,0.113320285,'2018-08-29 10:42:18'),
(12,0.038532321,'2018-08-29 10:42:18'),
(8,0.123430059,'2018-08-29 10:42:18'),
(11,0.625290389,'2018-08-29 10:42:18'),
(1,0.091823417,'2018-08-29 10:42:18'),
(9,0.246651097,'2018-08-29 10:42:19'),
(8,0.222901604,'2018-08-29 10:42:19'),
(13,1.600367041,'2018-08-29 10:42:20'),
(10,0.050076397,'2018-08-29 10:42:20'),
(14,0.460363958,'2018-08-29 10:42:20'),
(8,0.252590543,'2018-08-29 10:42:20'),
(15,0.144109113,'2018-08-29 10:42:20'),
(15,0.059993314,'2018-08-29 10:42:20'),
(16,0.058810662,'2018-08-29 10:42:20'),
(17,0.061824594,'2018-08-29 10:42:20'),
(16,0.074584583,'2018-08-29 10:42:20'),
(17,0.057086551,'2018-08-29 10:42:20'),
(18,0.020983572,'2018-08-29 10:42:20'),
(5,0.006504081,'2018-08-30 10:42:08'),
(3,0.202164333,'2018-08-30 10:42:08'),
(4,0.376675172,'2018-08-30 10:42:09'),
(1,0.413912204,'2018-08-30 10:42:09'),
(2,0.528427935,'2018-08-30 10:42:09'),
(6,0.11930188,'2018-08-30 10:42:14'),
(7,0.001062722,'2018-08-30 10:42:14'),
(7,0.004046882,'2018-08-30 10:42:14'),
(6,0.063360069,'2018-08-30 10:42:14'),
(8,0.168951416,'2018-08-30 10:42:16'),
(8,0.069032763,'2018-08-30 10:42:16'),
(9,0.47712966,'2018-08-30 10:42:16'),
(10,0.104510482,'2018-08-30 10:42:17'),
(10,0.062536146,'2018-08-30 10:42:17'),
(9,0.352823197,'2018-08-30 10:42:17'),
(8,0.38226374,'2018-08-30 10:42:17'),
(11,0.857324393,'2018-08-30 10:42:17'),
(12,0.113320285,'2018-08-30 10:42:18'),
(12,0.038532321,'2018-08-30 10:42:18'),
(8,0.123430059,'2018-08-30 10:42:18'),
(11,0.625290389,'2018-08-30 10:42:18'),
(1,0.091823417,'2018-08-30 10:42:18'),
(9,0.246651097,'2018-08-30 10:42:19'),
(8,0.222901604,'2018-08-30 10:42:19'),
(13,1.600367041,'2018-08-30 10:42:20'),
(10,0.050076397,'2018-08-30 10:42:20'),
(14,0.460363958,'2018-08-30 10:42:20'),
(8,0.252590543,'2018-08-30 10:42:20'),
(15,0.144109113,'2018-08-30 10:42:20'),
(15,0.059993314,'2018-08-30 10:42:20'),
(16,0.058810662,'2018-08-30 10:42:20'),
(17,0.061824594,'2018-08-30 10:42:20'),
(16,0.074584583,'2018-08-30 10:42:20'),
(17,0.057086551,'2018-08-30 10:42:20'),
(18,0.020983572,'2018-08-30 10:42:20'),
(5,0.006504081,'2018-08-31 10:42:08'),
(3,0.202164333,'2018-08-31 10:42:08'),
(4,0.376675172,'2018-08-31 10:42:09'),
(1,0.413912204,'2018-08-31 10:42:09'),
(2,0.528427935,'2018-08-31 10:42:09'),
(6,0.11930188,'2018-08-31 10:42:14'),
(7,0.001062722,'2018-08-31 10:42:14'),
(7,0.004046882,'2018-08-31 10:42:14'),
(6,0.063360069,'2018-08-31 10:42:14'),
(8,0.168951416,'2018-08-31 10:42:16'),
(8,0.069032763,'2018-08-31 10:42:16'),
(9,0.47712966,'2018-08-31 10:42:16'),
(10,0.104510482,'2018-08-31 10:42:17'),
(10,0.062536146,'2018-08-31 10:42:17'),
(9,0.352823197,'2018-08-31 10:42:17'),
(8,0.38226374,'2018-08-31 10:42:17'),
(11,0.857324393,'2018-08-31 10:42:17'),
(12,0.113320285,'2018-08-31 10:42:18'),
(12,0.038532321,'2018-08-31 10:42:18'),
(8,0.123430059,'2018-08-31 10:42:18'),
(11,0.625290389,'2018-08-31 10:42:18'),
(1,0.091823417,'2018-08-31 10:42:18'),
(9,0.246651097,'2018-08-31 10:42:19'),
(8,0.222901604,'2018-08-31 10:42:19'),
(13,1.600367041,'2018-08-31 10:42:20'),
(10,0.050076397,'2018-08-31 10:42:20'),
(14,0.460363958,'2018-08-31 10:42:20'),
(8,0.252590543,'2018-08-31 10:42:20'),
(15,0.144109113,'2018-08-31 10:42:20'),
(15,0.059993314,'2018-08-31 10:42:20'),
(16,0.058810662,'2018-08-31 10:42:20'),
(17,0.061824594,'2018-08-31 10:42:20'),
(16,0.074584583,'2018-08-31 10:42:20'),
(17,0.057086551,'2018-08-31 10:42:20'),
(18,0.020983572,'2018-08-31 10:42:20');
INSERT INTO failures (issue,method,service,created_at) VALUES
('HTTP Status Code 200 did not match 0','',18,'2018-08-28 10:42:14'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-28 10:42:14'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-29 10:42:14'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-30 10:42:14'),
('Incorrect Response','',1,'2018-08-31 10:40:14'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14'),
('HTTP Status Code 200 did not match 0','',18,'2018-08-31 10:42:14');
INSERT INTO communication (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
(1,'email','smtp.emailer.com',587,'exampleuser','password123','info@betatude.com','sendto@gmail.com','','',1,0,7,'2018-08-31 10:42:15'),
(2,'slack','https://webhooksurl.slack.com/***',0,'','','','','','',0,0,3,'2018-08-31 10:42:08'),
(3,'twilio','',0,'','','','','','',0,0,3,'2018-08-31 10:42:08');

142
dev/postgres_seed.sql Normal file
View File

@ -0,0 +1,142 @@
INSERT INTO core (name,description,config,api_key,api_secret,style,footer,domain,version,migration_id,use_cdn) VALUES ('Awesome Status','This is from the seed file!','config.yml','d2fead3e459bd14f570cf08527175b88b32d7faa','e351393306ea245de5f9588cbe8627c74db007c6','','Created by Hunter Long','DEV','',0,false);
INSERT INTO services (name,domain,check_type,method,port,expected,expected_status,check_interval,post_data,order_id,timeout,created_at) VALUES
('Google','https://google.com','http','GET',0,'',200,10,'',0,10,'2018-08-31 10:42:08.76390584-07:00'),
('Statup Github','https://github.com/hunterlong/statup','http','GET',0,'',200,30,'',0,20,'2018-08-31 10:42:08.764977938-07:00'),
('JSON Users Test','https://jsonplaceholder.typicode.com/users','http','GET',0,'',200,60,'',0,30,'2018-08-31 10:42:08.765794226-07:00'),
('JSON API Tester','https://jsonplaceholder.typicode.com/posts','http','POST',0,'(title)": "((\\"|[statup])*)"',201,30,'{ "title": "statup", "body": "bar", "userId": 19999 }',0,30,'2018-08-31 10:42:08.766542311-07:00'),
('Google DNS','8.8.8.8','tcp','',53,'',0,20,'',0,120,'2018-08-31 10:42:08.767327346-07:00'),
('The Bravery - An Honest Mistake','https://www.youtube.com/watch?v=O8vzbezVru4','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14.201305666-07:00'),
('Upper.io','https://upper.io/db.v3/','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14.201305666-07:00'),
('CoinApp Status','https://status.coinapp.io','http','GET',0,'',200,1,'',0,30,'2018-08-31 10:42:16.097416218-07:00'),
('Demo Page','https://demo.statup.io','http','GET',0,'',200,2,'',0,30,'2018-08-31 10:42:16.360051225-07:00'),
('Golang','https://golang.org','http','GET',0,'',200,3,'',0,30,'2018-08-31 10:42:16.923478722-07:00'),
('Github','https://github.com/hunterlong','http','GET',0,'',200,4,'',0,30,'2018-08-31 10:42:17.075544885-07:00'),
('Santa Monica','https://www.santamonica.com','http','GET',0,'',200,5,'',0,30,'2018-08-31 10:42:17.946947674-07:00'),
('Oeschs Die Dritten','https://www.oeschs-die-dritten.ch/en/','http','GET',0,'',200,6,'',0,30,'2018-08-31 10:42:18.083709297-07:00'),
('EtherScan.io','https://etherscan.io','http','GET',0,'',200,7,'',0,30,'2018-08-31 10:42:20.020969513-07:00'),
('Test Service 7','https://www.youtube.com/watch?v=ipvEIZMMILA','http','GET',0,'',200,8,'',0,30,'2018-08-31 10:42:20.50135711-07:00'),
('Test Service 8','https://www.youtube.com/watch?v=UdaYVxYF1Ok','http','GET',0,'',200,9,'',0,30,'2018-08-31 10:42:20.651218082-07:00'),
('Test Service 9','https://www.youtube.com/watch?v=yydZbVoCbn0&t=870s','http','GET',0,'',200,10,'',0,30,'2018-08-31 10:42:20.725479695-07:00'),
('Failing URL','http://failingdomainsarenofunatall.com','http','GET',0,'',200,11,'',0,30,'2018-08-31 10:42:20.799471402-07:00');
INSERT INTO users (username,password,email,api_key,api_secret,administrator,created_at) VALUES
('admin','$2a$14$Aye3yHae0ml6WRtvdgkRnO19OFze0IKF6IOHrdLpETtwLjnPelMUm','info@statup.io','27aa701119fb561d734eb4469cf13ba2550007e2','29de07014d32fbbbb80053ef3c19b464b2b72f64',true,'2018-08-31 10:42:07.684406458-07:00');
INSERT INTO hits (service,latency,created_at) VALUES
(5,0.006504081,'2018-08-29 10:42:08.779875117-07:00'),
(3,0.202164333,'2018-08-29 10:42:08.977187173-07:00'),
(4,0.376675172,'2018-08-29 10:42:09.151858662-07:00'),
(1,0.413912204,'2018-08-29 10:42:09.188850317-07:00'),
(1,0.473912204,'2018-08-29 10:42:10.118850317-07:00'),
(2,0.528427935,'2018-08-29 10:42:09.310642068-07:00'),
(6,0.11930188,'2018-08-29 10:42:14.133392018-07:00'),
(7,0.001062722,'2018-08-29 10:42:14.148258553-07:00'),
(7,0.004046882,'2018-08-29 10:42:14.156087817-07:00'),
(6,0.063360069,'2018-08-29 10:42:14.205383358-07:00'),
(8,0.168951416,'2018-08-29 10:42:16.346340211-07:00'),
(8,0.069032763,'2018-08-29 10:42:16.421634189-07:00'),
(9,0.47712966,'2018-08-29 10:42:16.91309317-07:00'),
(10,0.104510482,'2018-08-29 10:42:17.065673146-07:00'),
(10,0.062536146,'2018-08-29 10:42:17.134754949-07:00'),
(9,0.352823197,'2018-08-29 10:42:17.272174866-07:00'),
(8,0.38226374,'2018-08-29 10:42:17.738731999-07:00'),
(11,0.857324393,'2018-08-29 10:42:17.939738264-07:00'),
(12,0.113320285,'2018-08-29 10:42:18.073586363-07:00'),
(12,0.038532321,'2018-08-29 10:42:18.119730063-07:00'),
(8,0.123430059,'2018-08-29 10:42:18.479407581-07:00'),
(11,0.625290389,'2018-08-29 10:42:18.5715553-07:00'),
(1,0.091823417,'2018-08-29 10:42:18.868788983-07:00'),
(9,0.246651097,'2018-08-29 10:42:19.165697332-07:00'),
(8,0.222901604,'2018-08-29 10:42:19.57929225-07:00'),
(13,1.600367041,'2018-08-29 10:42:20.010203546-07:00'),
(10,0.050076397,'2018-08-29 10:42:20.12391038-07:00'),
(14,0.460363958,'2018-08-29 10:42:20.495937751-07:00'),
(8,0.252590543,'2018-08-29 10:42:20.609139136-07:00'),
(15,0.144109113,'2018-08-29 10:42:20.64756516-07:00'),
(15,0.059993314,'2018-08-29 10:42:20.710322678-07:00'),
(16,0.058810662,'2018-08-29 10:42:20.712087274-07:00'),
(17,0.061824594,'2018-08-29 10:42:20.791266761-07:00'),
(16,0.074584583,'2018-08-29 10:42:20.797581163-07:00'),
(17,0.057086551,'2018-08-29 10:42:20.854020864-07:00'),
(18,0.020983572,'2018-08-29 10:42:20.864610424-07:00'),
(5,0.006504081,'2018-08-30 10:42:08.779875117-07:00'),
(3,0.202164333,'2018-08-30 10:42:08.977187173-07:00'),
(4,0.376675172,'2018-08-30 10:42:09.151858662-07:00'),
(1,0.413912204,'2018-08-30 10:42:09.188850317-07:00'),
(2,0.528427935,'2018-08-30 10:42:09.310642068-07:00'),
(6,0.11930188,'2018-08-30 10:42:14.133392018-07:00'),
(7,0.001062722,'2018-08-30 10:42:14.148258553-07:00'),
(7,0.004046882,'2018-08-30 10:42:14.156087817-07:00'),
(6,0.063360069,'2018-08-30 10:42:14.205383358-07:00'),
(8,0.168951416,'2018-08-30 10:42:16.346340211-07:00'),
(8,0.069032763,'2018-08-30 10:42:16.421634189-07:00'),
(9,0.47712966,'2018-08-30 10:42:16.91309317-07:00'),
(10,0.104510482,'2018-08-30 10:42:17.065673146-07:00'),
(10,0.062536146,'2018-08-30 10:42:17.134754949-07:00'),
(9,0.352823197,'2018-08-30 10:42:17.272174866-07:00'),
(8,0.38226374,'2018-08-30 10:42:17.738731999-07:00'),
(11,0.857324393,'2018-08-30 10:42:17.939738264-07:00'),
(12,0.113320285,'2018-08-30 10:42:18.073586363-07:00'),
(12,0.038532321,'2018-08-30 10:42:18.119730063-07:00'),
(8,0.123430059,'2018-08-30 10:42:18.479407581-07:00'),
(11,0.625290389,'2018-08-30 10:42:18.5715553-07:00'),
(1,0.091823417,'2018-08-30 10:42:18.868788983-07:00'),
(9,0.246651097,'2018-08-30 10:42:19.165697332-07:00'),
(8,0.222901604,'2018-08-30 10:42:19.57929225-07:00'),
(13,1.600367041,'2018-08-30 10:42:20.010203546-07:00'),
(10,0.050076397,'2018-08-30 10:42:20.12391038-07:00'),
(14,0.460363958,'2018-08-30 10:42:20.495937751-07:00'),
(8,0.252590543,'2018-08-30 10:42:20.609139136-07:00'),
(15,0.144109113,'2018-08-30 10:42:20.64756516-07:00'),
(15,0.059993314,'2018-08-30 10:42:20.710322678-07:00'),
(16,0.058810662,'2018-08-30 10:42:20.712087274-07:00'),
(17,0.061824594,'2018-08-30 10:42:20.791266761-07:00'),
(16,0.074584583,'2018-08-30 10:42:20.797581163-07:00'),
(17,0.057086551,'2018-08-30 10:42:20.854020864-07:00'),
(18,0.020983572,'2018-08-30 10:42:20.864610424-07:00'),
(5,0.006504081,'2018-08-31 10:42:08.779875117-07:00'),
(3,0.202164333,'2018-08-31 10:42:08.977187173-07:00'),
(4,0.376675172,'2018-08-31 10:42:09.151858662-07:00'),
(1,0.413912204,'2018-08-31 10:42:09.188850317-07:00'),
(2,0.528427935,'2018-08-31 10:42:09.310642068-07:00'),
(6,0.11930188,'2018-08-31 10:42:14.133392018-07:00'),
(7,0.001062722,'2018-08-31 10:42:14.148258553-07:00'),
(7,0.004046882,'2018-08-31 10:42:14.156087817-07:00'),
(6,0.063360069,'2018-08-31 10:42:14.205383358-07:00'),
(8,0.168951416,'2018-08-31 10:42:16.346340211-07:00'),
(8,0.069032763,'2018-08-31 10:42:16.421634189-07:00'),
(9,0.47712966,'2018-08-31 10:42:16.91309317-07:00'),
(10,0.104510482,'2018-08-31 10:42:17.065673146-07:00'),
(10,0.062536146,'2018-08-31 10:42:17.134754949-07:00'),
(9,0.352823197,'2018-08-31 10:42:17.272174866-07:00'),
(8,0.38226374,'2018-08-31 10:42:17.738731999-07:00'),
(11,0.857324393,'2018-08-31 10:42:17.939738264-07:00'),
(12,0.113320285,'2018-08-31 10:42:18.073586363-07:00'),
(12,0.038532321,'2018-08-31 10:42:18.119730063-07:00'),
(8,0.123430059,'2018-08-31 10:42:18.479407581-07:00'),
(11,0.625290389,'2018-08-31 10:42:18.5715553-07:00'),
(1,0.091823417,'2018-08-31 10:42:18.868788983-07:00'),
(9,0.246651097,'2018-08-31 10:42:19.165697332-07:00'),
(8,0.222901604,'2018-08-31 10:42:19.57929225-07:00'),
(13,1.600367041,'2018-08-31 10:42:20.010203546-07:00'),
(10,0.050076397,'2018-08-31 10:42:20.12391038-07:00'),
(14,0.460363958,'2018-08-31 10:42:20.495937751-07:00'),
(8,0.252590543,'2018-08-31 10:42:20.609139136-07:00'),
(15,0.144109113,'2018-08-31 10:42:20.64756516-07:00'),
(15,0.059993314,'2018-08-31 10:42:20.710322678-07:00'),
(16,0.058810662,'2018-08-31 10:42:20.712087274-07:00'),
(17,0.061824594,'2018-08-31 10:42:20.791266761-07:00'),
(16,0.074584583,'2018-08-31 10:42:20.797581163-07:00'),
(17,0.057086551,'2018-08-31 10:42:20.854020864-07:00'),
(18,0.020983572,'2018-08-31 10:42:20.864610424-07:00');
INSERT INTO failures (issue,method,service,created_at) VALUES
('HTTP Status Code 200 did not match 0','',18,'2018-08-28 10:42:14.271162743-07:00'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-28 10:42:14.271162743-07:00'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-29 10:42:14.271162743-07:00'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-30 10:42:14.271162743-07:00'),
('Incorrect Response','',1,'2018-08-31 10:40:14.272209564-07:00'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.271162743-07:00'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.272209564-07:00'),
('HTTP Status Code 200 did not match 0','',18,'2018-08-31 10:42:14.271162743-07:00');
INSERT INTO communication (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
(1,'email','smtp.emailer.com',587,'exampleuser','password123','info@betatude.com','sendto@gmail.com','','',true,false,7,'2018-08-31 10:42:15.000829706-07:00'),
(2,'slack','https://webhooksurl.slack.com/***',0,'','','','','','',false,false,3,'2018-08-31 10:42:08.775366824-07:00'),
(3,'twilio','',0,'','','','','','',false,false,3,'2018-08-31 10:42:08.776944923-07:00');

142
dev/sqlite_seed.sql Normal file
View File

@ -0,0 +1,142 @@
INSERT INTO core (name,description,config,api_key,api_secret,style,footer,domain,version,migration_id,use_cdn) VALUES ('Awesome Status','This is from the seed file!','config.yml','d2fead3e459bd14f570cf08527175b88b32d7faa','e351393306ea245de5f9588cbe8627c74db007c6','','Created by Hunter Long','','',0,0);
INSERT INTO services (id,name,domain,check_type,method,port,expected,expected_status,check_interval,post_data,order_id,timeout,created_at) VALUES
(1,'Google','https://google.com','http','GET',0,'',200,10,'',0,10,'2018-08-31 10:42:08.76390584-07:00'),
(2,'Statup Github','https://github.com/hunterlong/statup','http','GET',0,'',200,30,'',0,20,'2018-08-31 10:42:08.764977938-07:00'),
(3,'JSON Users Test','https://jsonplaceholder.typicode.com/users','http','GET',0,'',200,60,'',0,30,'2018-08-31 10:42:08.765794226-07:00'),
(4,'JSON API Tester','https://jsonplaceholder.typicode.com/posts','http','POST',0,'(title)": "((\\"|[statup])*)"',201,30,'{ "title": "statup", "body": "bar", "userId": 19999 }',0,30,'2018-08-31 10:42:08.766542311-07:00'),
(5,'Google DNS','8.8.8.8','tcp','',53,'',0,20,'',0,120,'2018-08-31 10:42:08.767327346-07:00'),
(6,'The Bravery - An Honest Mistake','https://www.youtube.com/watch?v=O8vzbezVru4','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14.201305666-07:00'),
(7,'Upper.io','https://upper.io/db.v3/','http','GET',0,'',0,30,'',0,15,'2018-08-31 10:42:14.201305666-07:00'),
(8,'CoinApp Status','https://status.coinapp.io','http','GET',0,'',200,1,'',0,30,'2018-08-31 10:42:16.097416218-07:00'),
(9,'Demo Page','https://demo.statup.io','http','GET',0,'',200,2,'',0,30,'2018-08-31 10:42:16.360051225-07:00'),
(10,'Golang','https://golang.org','http','GET',0,'',200,3,'',0,30,'2018-08-31 10:42:16.923478722-07:00'),
(11,'Github','https://github.com/hunterlong','http','GET',0,'',200,4,'',0,30,'2018-08-31 10:42:17.075544885-07:00'),
(12,'Santa Monica','https://www.santamonica.com','http','GET',0,'',200,5,'',0,30,'2018-08-31 10:42:17.946947674-07:00'),
(13,'Oeschs Die Dritten','https://www.oeschs-die-dritten.ch/en/','http','GET',0,'',200,6,'',0,30,'2018-08-31 10:42:18.083709297-07:00'),
(14,'EtherScan.io','https://etherscan.io','http','GET',0,'',200,7,'',0,30,'2018-08-31 10:42:20.020969513-07:00'),
(15,'Test Service 7','https://www.youtube.com/watch?v=ipvEIZMMILA','http','GET',0,'',200,8,'',0,30,'2018-08-31 10:42:20.50135711-07:00'),
(16,'Test Service 8','https://www.youtube.com/watch?v=UdaYVxYF1Ok','http','GET',0,'',200,9,'',0,30,'2018-08-31 10:42:20.651218082-07:00'),
(17,'Test Service 9','https://www.youtube.com/watch?v=yydZbVoCbn0&t=870s','http','GET',0,'',200,10,'',0,30,'2018-08-31 10:42:20.725479695-07:00'),
(18,'Failing URL','http://failingdomainsarenofunatall.com','http','GET',0,'',200,11,'',0,30,'2018-08-31 10:42:20.799471402-07:00');
INSERT INTO users (username,password,email,api_key,api_secret,administrator,created_at) VALUES
('admin','$2a$14$Aye3yHae0ml6WRtvdgkRnO19OFze0IKF6IOHrdLpETtwLjnPelMUm','info@statup.io','27aa701119fb561d734eb4469cf13ba2550007e2','29de07014d32fbbbb80053ef3c19b464b2b72f64',1,'2018-08-31 10:42:07.684406458-07:00');
INSERT INTO hits (service,latency,created_at) VALUES
(5,0.006504081,'2018-08-29 10:42:08.779875117-07:00'),
(3,0.202164333,'2018-08-29 10:42:08.977187173-07:00'),
(4,0.376675172,'2018-08-29 10:42:09.151858662-07:00'),
(1,0.413912204,'2018-08-29 10:42:09.188850317-07:00'),
(1,0.473912204,'2018-08-29 10:42:10.118850317-07:00'),
(2,0.528427935,'2018-08-29 10:42:09.310642068-07:00'),
(6,0.11930188,'2018-08-29 10:42:14.133392018-07:00'),
(7,0.001062722,'2018-08-29 10:42:14.148258553-07:00'),
(7,0.004046882,'2018-08-29 10:42:14.156087817-07:00'),
(6,0.063360069,'2018-08-29 10:42:14.205383358-07:00'),
(8,0.168951416,'2018-08-29 10:42:16.346340211-07:00'),
(8,0.069032763,'2018-08-29 10:42:16.421634189-07:00'),
(9,0.47712966,'2018-08-29 10:42:16.91309317-07:00'),
(10,0.104510482,'2018-08-29 10:42:17.065673146-07:00'),
(10,0.062536146,'2018-08-29 10:42:17.134754949-07:00'),
(9,0.352823197,'2018-08-29 10:42:17.272174866-07:00'),
(8,0.38226374,'2018-08-29 10:42:17.738731999-07:00'),
(11,0.857324393,'2018-08-29 10:42:17.939738264-07:00'),
(12,0.113320285,'2018-08-29 10:42:18.073586363-07:00'),
(12,0.038532321,'2018-08-29 10:42:18.119730063-07:00'),
(8,0.123430059,'2018-08-29 10:42:18.479407581-07:00'),
(11,0.625290389,'2018-08-29 10:42:18.5715553-07:00'),
(1,0.091823417,'2018-08-29 10:42:18.868788983-07:00'),
(9,0.246651097,'2018-08-29 10:42:19.165697332-07:00'),
(8,0.222901604,'2018-08-29 10:42:19.57929225-07:00'),
(13,1.600367041,'2018-08-29 10:42:20.010203546-07:00'),
(10,0.050076397,'2018-08-29 10:42:20.12391038-07:00'),
(14,0.460363958,'2018-08-29 10:42:20.495937751-07:00'),
(8,0.252590543,'2018-08-29 10:42:20.609139136-07:00'),
(15,0.144109113,'2018-08-29 10:42:20.64756516-07:00'),
(15,0.059993314,'2018-08-29 10:42:20.710322678-07:00'),
(16,0.058810662,'2018-08-29 10:42:20.712087274-07:00'),
(17,0.061824594,'2018-08-29 10:42:20.791266761-07:00'),
(16,0.074584583,'2018-08-29 10:42:20.797581163-07:00'),
(17,0.057086551,'2018-08-29 10:42:20.854020864-07:00'),
(18,0.020983572,'2018-08-29 10:42:20.864610424-07:00'),
(5,0.006504081,'2018-08-30 10:42:08.779875117-07:00'),
(3,0.202164333,'2018-08-30 10:42:08.977187173-07:00'),
(4,0.376675172,'2018-08-30 10:42:09.151858662-07:00'),
(1,0.413912204,'2018-08-30 10:42:09.188850317-07:00'),
(2,0.528427935,'2018-08-30 10:42:09.310642068-07:00'),
(6,0.11930188,'2018-08-30 10:42:14.133392018-07:00'),
(7,0.001062722,'2018-08-30 10:42:14.148258553-07:00'),
(7,0.004046882,'2018-08-30 10:42:14.156087817-07:00'),
(6,0.063360069,'2018-08-30 10:42:14.205383358-07:00'),
(8,0.168951416,'2018-08-30 10:42:16.346340211-07:00'),
(8,0.069032763,'2018-08-30 10:42:16.421634189-07:00'),
(9,0.47712966,'2018-08-30 10:42:16.91309317-07:00'),
(10,0.104510482,'2018-08-30 10:42:17.065673146-07:00'),
(10,0.062536146,'2018-08-30 10:42:17.134754949-07:00'),
(9,0.352823197,'2018-08-30 10:42:17.272174866-07:00'),
(8,0.38226374,'2018-08-30 10:42:17.738731999-07:00'),
(11,0.857324393,'2018-08-30 10:42:17.939738264-07:00'),
(12,0.113320285,'2018-08-30 10:42:18.073586363-07:00'),
(12,0.038532321,'2018-08-30 10:42:18.119730063-07:00'),
(8,0.123430059,'2018-08-30 10:42:18.479407581-07:00'),
(11,0.625290389,'2018-08-30 10:42:18.5715553-07:00'),
(1,0.091823417,'2018-08-30 10:42:18.868788983-07:00'),
(9,0.246651097,'2018-08-30 10:42:19.165697332-07:00'),
(8,0.222901604,'2018-08-30 10:42:19.57929225-07:00'),
(13,1.600367041,'2018-08-30 10:42:20.010203546-07:00'),
(10,0.050076397,'2018-08-30 10:42:20.12391038-07:00'),
(14,0.460363958,'2018-08-30 10:42:20.495937751-07:00'),
(8,0.252590543,'2018-08-30 10:42:20.609139136-07:00'),
(15,0.144109113,'2018-08-30 10:42:20.64756516-07:00'),
(15,0.059993314,'2018-08-30 10:42:20.710322678-07:00'),
(16,0.058810662,'2018-08-30 10:42:20.712087274-07:00'),
(17,0.061824594,'2018-08-30 10:42:20.791266761-07:00'),
(16,0.074584583,'2018-08-30 10:42:20.797581163-07:00'),
(17,0.057086551,'2018-08-30 10:42:20.854020864-07:00'),
(18,0.020983572,'2018-08-30 10:42:20.864610424-07:00'),
(5,0.006504081,'2018-08-31 10:42:08.779875117-07:00'),
(3,0.202164333,'2018-08-31 10:42:08.977187173-07:00'),
(4,0.376675172,'2018-08-31 10:42:09.151858662-07:00'),
(1,0.413912204,'2018-08-31 10:42:09.188850317-07:00'),
(2,0.528427935,'2018-08-31 10:42:09.310642068-07:00'),
(6,0.11930188,'2018-08-31 10:42:14.133392018-07:00'),
(7,0.001062722,'2018-08-31 10:42:14.148258553-07:00'),
(7,0.004046882,'2018-08-31 10:42:14.156087817-07:00'),
(6,0.063360069,'2018-08-31 10:42:14.205383358-07:00'),
(8,0.168951416,'2018-08-31 10:42:16.346340211-07:00'),
(8,0.069032763,'2018-08-31 10:42:16.421634189-07:00'),
(9,0.47712966,'2018-08-31 10:42:16.91309317-07:00'),
(10,0.104510482,'2018-08-31 10:42:17.065673146-07:00'),
(10,0.062536146,'2018-08-31 10:42:17.134754949-07:00'),
(9,0.352823197,'2018-08-31 10:42:17.272174866-07:00'),
(8,0.38226374,'2018-08-31 10:42:17.738731999-07:00'),
(11,0.857324393,'2018-08-31 10:42:17.939738264-07:00'),
(12,0.113320285,'2018-08-31 10:42:18.073586363-07:00'),
(12,0.038532321,'2018-08-31 10:42:18.119730063-07:00'),
(8,0.123430059,'2018-08-31 10:42:18.479407581-07:00'),
(11,0.625290389,'2018-08-31 10:42:18.5715553-07:00'),
(1,0.091823417,'2018-08-31 10:42:18.868788983-07:00'),
(9,0.246651097,'2018-08-31 10:42:19.165697332-07:00'),
(8,0.222901604,'2018-08-31 10:42:19.57929225-07:00'),
(13,1.600367041,'2018-08-31 10:42:20.010203546-07:00'),
(10,0.050076397,'2018-08-31 10:42:20.12391038-07:00'),
(14,0.460363958,'2018-08-31 10:42:20.495937751-07:00'),
(8,0.252590543,'2018-08-31 10:42:20.609139136-07:00'),
(15,0.144109113,'2018-08-31 10:42:20.64756516-07:00'),
(15,0.059993314,'2018-08-31 10:42:20.710322678-07:00'),
(16,0.058810662,'2018-08-31 10:42:20.712087274-07:00'),
(17,0.061824594,'2018-08-31 10:42:20.791266761-07:00'),
(16,0.074584583,'2018-08-31 10:42:20.797581163-07:00'),
(17,0.057086551,'2018-08-31 10:42:20.854020864-07:00'),
(18,0.020983572,'2018-08-31 10:42:20.864610424-07:00');
INSERT INTO failures (issue,method,service,created_at) VALUES
('HTTP Status Code 200 did not match 0','',18,'2018-08-28 10:42:14.271162743-07:00'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-28 10:42:14.271162743-07:00'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-29 10:42:14.271162743-07:00'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-30 10:42:14.271162743-07:00'),
('Incorrect Response','',1,'2018-08-31 10:40:14.272209564-07:00'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.271162743-07:00'),
('HTTP Status Code 200 did not match 0','',6,'2018-08-31 10:42:14.272209564-07:00'),
('HTTP Status Code 200 did not match 0','',18,'2018-08-31 10:42:14.271162743-07:00');
INSERT INTO communication (id,method,host,port,username,password,var1,var2,api_key,api_secret,enabled,removable,limits,created_at) VALUES
(1,'email','smtp.emailer.com',587,'exampleuser','password123','info@betatude.com','sendto@gmail.com','','',1,0,7,'2018-08-31 10:42:15.000829706-07:00'),
(2,'slack','https://webhooksurl.slack.com/***',0,'','','','','','',0,0,3,'2018-08-31 10:42:08.775366824-07:00'),
(3,'twilio','',0,'','','','','','',0,0,3,'2018-08-31 10:42:08.776944923-07:00');

View File

@ -36,17 +36,23 @@ const (
func injectDatabase() { func injectDatabase() {
core.NewCore() core.NewCore()
core.Configs = new(types.Config) core.Configs = new(core.DbConfig)
core.Configs.Connection = "sqlite" core.Configs.DbConn = "sqlite"
core.CoreApp.DbConnection = "sqlite" core.CoreApp.DbConnection = "sqlite"
core.CoreApp.Version = "DEV" core.CoreApp.Version = "DEV"
core.DbConnection("sqlite", false, utils.Directory) core.Configs.Connect(false, utils.Directory)
core.InitApp() core.InitApp()
} }
func Clean() {
utils.DeleteFile(dir + "/config.yml")
utils.DeleteFile(dir + "/statup.db")
utils.DeleteDirectory(dir + "/assets")
utils.DeleteDirectory(dir + "/logs")
}
func TestInit(t *testing.T) { func TestInit(t *testing.T) {
t.SkipNow() Clean()
injectDatabase()
} }
func formatJSON(res string, out interface{}) { func formatJSON(res string, out interface{}) {

View File

@ -97,6 +97,8 @@ func TestProcessSetupHandler(t *testing.T) {
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
Router().ServeHTTP(rr, req) Router().ServeHTTP(rr, req)
assert.Equal(t, 303, rr.Code) assert.Equal(t, 303, rr.Code)
assert.FileExists(t, dir+"/config.yml")
assert.FileExists(t, dir+"/statup.db")
} }
func TestCheckSetupHandler(t *testing.T) { func TestCheckSetupHandler(t *testing.T) {
@ -143,7 +145,9 @@ func TestServiceChartHandler(t *testing.T) {
assert.Equal(t, 200, rr.Code) assert.Equal(t, 200, rr.Code)
t.Log(body) t.Log(body)
assert.Contains(t, body, "var ctx_1") 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_3")
assert.Contains(t, body, "var ctx_4")
assert.Contains(t, body, "var ctx_5") assert.Contains(t, body, "var ctx_5")
} }

View File

@ -27,7 +27,7 @@ type index struct {
} }
func IndexHandler(w http.ResponseWriter, r *http.Request) { func IndexHandler(w http.ResponseWriter, r *http.Request) {
if core.CoreApp.DbConnection == "" { if core.Configs == nil {
http.Redirect(w, r, "/setup", http.StatusSeeOther) http.Redirect(w, r, "/setup", http.StatusSeeOther)
return return
} }
@ -42,12 +42,12 @@ func DesktopInit(ip string, port int) {
var err error var err error
exists := utils.FileExists(utils.Directory + "/statup.db") exists := utils.FileExists(utils.Directory + "/statup.db")
if exists { if exists {
core.Configs, err = core.LoadConfig() core.Configs, err = core.LoadConfig(utils.Directory)
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
return return
} }
err = core.DbConnection(core.Configs.Connection, false, utils.Directory) err = core.Configs.Connect(false, utils.Directory)
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
return return
@ -68,24 +68,28 @@ func DesktopInit(ip string, port int) {
Location: utils.Directory, Location: utils.Directory,
}} }}
err = config.Save() config, err = config.Save()
if err != nil { if err != nil {
utils.Log(4, err) utils.Log(4, err)
} }
config.DropDatabase()
config.CreateDatabase()
core.CoreApp = config.CreateCore()
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
return return
} }
core.Configs, err = core.LoadConfig() core.Configs, err = core.LoadConfig(utils.Directory)
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
config.Error = err config.Error = err
return return
} }
err = core.DbConnection(core.Configs.Connection, false, utils.Directory) err = core.Configs.Connect(false, utils.Directory)
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
core.DeleteConfig() core.DeleteConfig()

View File

@ -16,7 +16,6 @@
package handlers package handlers
import ( import (
"github.com/hunterlong/statup/core"
"net/http" "net/http"
"strings" "strings"
) )
@ -53,6 +52,6 @@ func PluginsDownloadHandler(w http.ResponseWriter, r *http.Request) {
//vars := mux.Vars(router) //vars := mux.Vars(router)
//name := vars["name"] //name := vars["name"]
//DownloadPlugin(name) //DownloadPlugin(name)
core.LoadConfig() //core.LoadConfig(utils.Directory)
http.Redirect(w, r, "/plugins", http.StatusSeeOther) http.Redirect(w, r, "/plugins", http.StatusSeeOther)
} }

View File

@ -61,13 +61,6 @@ func PrometheusHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(output)) w.Write([]byte(output))
} }
func ResetDbHandler(w http.ResponseWriter, r *http.Request) {
utils.Log(1, fmt.Sprintf("Prometheus /metrics Request From IP: %v\n", r.RemoteAddr))
core.DropDatabase()
core.CoreApp = nil
w.WriteHeader(http.StatusOK)
}
func isAuthorized(r *http.Request) bool { func isAuthorized(r *http.Request) bool {
var token string var token string
tokens, ok := r.Header["Authorization"] tokens, ok := r.Header["Authorization"]

View File

@ -51,7 +51,6 @@ func Router() *mux.Router {
r.Handle("/setup", http.HandlerFunc(SetupHandler)).Methods("GET") r.Handle("/setup", http.HandlerFunc(SetupHandler)).Methods("GET")
r.Handle("/setup", http.HandlerFunc(ProcessSetupHandler)).Methods("POST") r.Handle("/setup", http.HandlerFunc(ProcessSetupHandler)).Methods("POST")
r.Handle("/dashboard", http.HandlerFunc(DashboardHandler)).Methods("GET") r.Handle("/dashboard", http.HandlerFunc(DashboardHandler)).Methods("GET")
//r.Handle("/backups/create", http.HandlerFunc(BackupCreateHandler)).Methods("GET")
r.Handle("/dashboard", http.HandlerFunc(LoginHandler)).Methods("POST") r.Handle("/dashboard", http.HandlerFunc(LoginHandler)).Methods("POST")
r.Handle("/logout", http.HandlerFunc(LogoutHandler)) r.Handle("/logout", http.HandlerFunc(LogoutHandler))
r.Handle("/services", http.HandlerFunc(ServicesHandler)).Methods("GET") r.Handle("/services", http.HandlerFunc(ServicesHandler)).Methods("GET")

View File

@ -60,8 +60,7 @@ func ReorderServiceHandler(w http.ResponseWriter, r *http.Request) {
decoder.Decode(&newOrder) decoder.Decode(&newOrder)
for _, s := range newOrder { for _, s := range newOrder {
service := core.SelectService(s.Id) service := core.SelectService(s.Id)
service.Order = s.Order service.UpdateSingle("order_id", s.Order)
service.Update(false)
} }
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }

View File

@ -16,7 +16,6 @@
package handlers package handlers
import ( import (
"fmt"
"github.com/hunterlong/statup/core" "github.com/hunterlong/statup/core"
"github.com/hunterlong/statup/types" "github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
@ -56,6 +55,7 @@ func SetupHandler(w http.ResponseWriter, r *http.Request) {
} }
func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) { func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
var err error
if core.CoreApp.Services() != nil { if core.CoreApp.Services() != nil {
http.Redirect(w, r, "/", http.StatusSeeOther) http.Redirect(w, r, "/", http.StatusSeeOther)
return return
@ -75,7 +75,9 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
domain := r.PostForm.Get("domain") domain := r.PostForm.Get("domain")
email := r.PostForm.Get("email") email := r.PostForm.Get("email")
config := &core.DbConfig{&types.DbConfig{ dir := utils.Directory
config := &core.DbConfig{DbConfig: &types.DbConfig{
DbConn: dbConn, DbConn: dbConn,
DbHost: dbHost, DbHost: dbHost,
DbUser: dbUser, DbUser: dbUser,
@ -92,13 +94,15 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
Location: utils.Directory, Location: utils.Directory,
}} }}
fmt.Println(config) core.Configs, err = config.Save()
err := config.Save()
if err != nil { if err != nil {
utils.Log(4, err) utils.Log(4, err)
config.Error = err
SetupResponseError(w, r, config)
return
} }
core.Configs, err = core.LoadConfig(dir)
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(3, err)
config.Error = err config.Error = err
@ -106,23 +110,26 @@ func ProcessSetupHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
core.Configs, err = core.LoadConfig() err = core.Configs.Connect(false, dir)
if err != nil { if err != nil {
utils.Log(3, err) utils.Log(4, err)
config.Error = err
SetupResponseError(w, r, config)
return
}
err = core.DbConnection(core.Configs.Connection, false, utils.Directory)
if err != nil {
utils.Log(3, err)
core.DeleteConfig() core.DeleteConfig()
config.Error = err config.Error = err
SetupResponseError(w, r, config) SetupResponseError(w, r, config)
return return
} }
config.DropDatabase()
config.CreateDatabase()
core.CoreApp, err = config.InsertCore()
if err != nil {
utils.Log(4, err)
config.Error = err
SetupResponseError(w, r, config)
return
}
admin := core.ReturnUser(&types.User{ admin := core.ReturnUser(&types.User{
Username: config.Username, Username: config.Username,
Password: config.Password, Password: config.Password,

View File

@ -215,7 +215,7 @@ func (u *Email) OnSave() error {
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS // ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
func (u *Email) Install() error { func (u *Email) Install() error {
inDb, err := emailer.Notification.IsInDatabase() inDb := emailer.Notification.IsInDatabase()
if !inDb { if !inDb {
newNotifer, err := InsertDatabase(u.Notification) newNotifer, err := InsertDatabase(u.Notification)
if err != nil { if err != nil {
@ -224,7 +224,7 @@ func (u *Email) Install() error {
} }
utils.Log(1, fmt.Sprintf("new notifier #%v installed: %v", newNotifer, u.Method)) utils.Log(1, fmt.Sprintf("new notifier #%v installed: %v", newNotifer, u.Method))
} }
return err return nil
} }
func (u *Email) dialSend(email *EmailOutgoing) error { func (u *Email) dialSend(email *EmailOutgoing) error {

View File

@ -19,34 +19,34 @@ import (
"fmt" "fmt"
"github.com/hunterlong/statup/types" "github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"github.com/jinzhu/gorm"
"strings" "strings"
"time" "time"
"upper.io/db.v3"
) )
var ( var (
AllCommunications []types.AllNotifiers AllCommunications []types.AllNotifiers
Collections db.Collection Collections *gorm.DB
Logs []*NotificationLog Logs []*NotificationLog
) )
type Notification struct { type Notification struct {
Id int64 `db:"id,omitempty" json:"id"` Id int64 `gorm:"primary_key column:id" json:"id"`
Method string `db:"method" json:"method"` Method string `gorm:"column:method" json:"method"`
Host string `db:"host" json:"-"` Host string `gorm:"column:host" json:"-"`
Port int `db:"port" json:"-"` Port int `gorm:"column:port" json:"-"`
Username string `db:"username" json:"-"` Username string `gorm:"column:username" json:"-"`
Password string `db:"password" json:"-"` Password string `gorm:"column:password" json:"-"`
Var1 string `db:"var1" json:"-"` Var1 string `gorm:"column:var1" json:"-"`
Var2 string `db:"var2" json:"-"` Var2 string `gorm:"column:var2" json:"-"`
ApiKey string `db:"api_key" json:"-"` ApiKey string `gorm:"column:api_key" json:"-"`
ApiSecret string `db:"api_secret" json:"-"` ApiSecret string `gorm:"column:api_secret" json:"-"`
Enabled bool `db:"enabled" json:"enabled"` Enabled bool `gorm:"column:enabled" json:"enabled"`
Limits int `db:"limits" json:"-"` Limits int `gorm:"column:limits" json:"-"`
Removable bool `db:"removable" json:"-"` Removable bool `gorm:"column:removable" json:"-"`
CreatedAt time.Time `db:"created_at" json:"created_at"` CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
Form []NotificationForm Form []NotificationForm `gorm:"-" json:"-"`
Routine chan struct{} Routine chan struct{} `gorm:"-" json:"-"`
} }
type Notifier interface { type Notifier interface {
@ -115,30 +115,30 @@ func reverseLogs(input []*NotificationLog) []*NotificationLog {
return append(reverseLogs(input[1:]), input[0]) return append(reverseLogs(input[1:]), input[0])
} }
func (n *Notification) IsInDatabase() (bool, error) { func (n *Notification) IsInDatabase() bool {
return Collections.Find("id", n.Id).Exists() return !Collections.Find(n).RecordNotFound()
} }
func SelectNotification(id int64) (*Notification, error) { func SelectNotification(id int64) (*Notification, error) {
var notifier *Notification var notifier Notification
err := Collections.Find("id", id).One(&notifier) err := Collections.Find(&notifier, id)
return notifier, err return &notifier, err.Error
} }
func (n *Notification) Update() (*Notification, error) { func (n *Notification) Update() (*Notification, error) {
n.CreatedAt = time.Now() n.CreatedAt = time.Now()
err := Collections.Find("id", n.Id).Update(n) err := Collections.Update(n)
return n, err return n, err.Error
} }
func InsertDatabase(n *Notification) (int64, error) { func InsertDatabase(n *Notification) (int64, error) {
n.CreatedAt = time.Now() n.CreatedAt = time.Now()
n.Limits = 3 n.Limits = 3
newId, err := Collections.Insert(n) db := Collections.Create(n)
if err != nil { if db.Error != nil {
return 0, err return 0, db.Error
} }
return newId.(int64), err return n.Id, db.Error
} }
func SelectNotifier(id int64) Notifier { func SelectNotifier(id int64) Notifier {

View File

@ -18,10 +18,12 @@ package notifiers
import ( import (
"github.com/hunterlong/statup/types" "github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils" "github.com/hunterlong/statup/utils"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
_ "github.com/mattn/go-sqlite3"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"testing" "testing"
"upper.io/db.v3/sqlite"
) )
var ( var (
@ -67,11 +69,8 @@ func init() {
} }
func injectDatabase() { func injectDatabase() {
sqliteDb := sqlite.ConnectionURL{ dbSession, _ := gorm.Open("sqlite3", dir+"/statup.db")
Database: dir + "/statup.db", Collections = dbSession.Table("communication").Model(&Notification{})
}
dbSession, _ := sqlite.Open(sqliteDb)
Collections = dbSession.Collection("communication")
} }
type Tester struct { type Tester struct {
@ -100,8 +99,7 @@ func TestAdd(t *testing.T) {
} }
func TestIsInDatabase(t *testing.T) { func TestIsInDatabase(t *testing.T) {
in, err := testNotifier.IsInDatabase() in := testNotifier.IsInDatabase()
assert.Nil(t, err)
assert.False(t, in) assert.False(t, in)
} }
@ -110,8 +108,7 @@ func TestInsertDatabase(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
assert.NotZero(t, newId) assert.NotZero(t, newId)
in, err := testNotifier.IsInDatabase() in := testNotifier.IsInDatabase()
assert.Nil(t, err)
assert.True(t, in) assert.True(t, in)
} }

View File

@ -165,7 +165,7 @@ func (u *Slack) OnSave() error {
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS // ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
func (u *Slack) Install() error { func (u *Slack) Install() error {
inDb, err := slacker.Notification.IsInDatabase() inDb := slacker.Notification.IsInDatabase()
if !inDb { if !inDb {
newNotifer, err := InsertDatabase(u.Notification) newNotifer, err := InsertDatabase(u.Notification)
if err != nil { if err != nil {
@ -174,5 +174,5 @@ func (u *Slack) Install() error {
} }
utils.Log(1, fmt.Sprintf("new notifier #%v installed: %v", newNotifer, u.Method)) utils.Log(1, fmt.Sprintf("new notifier #%v installed: %v", newNotifer, u.Method))
} }
return err return nil
} }

View File

@ -179,7 +179,7 @@ func (u *Twilio) OnSave() error {
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS // ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
func (u *Twilio) Install() error { func (u *Twilio) Install() error {
inDb, err := twilio.Notification.IsInDatabase() inDb := twilio.Notification.IsInDatabase()
if !inDb { if !inDb {
newNotifer, err := InsertDatabase(u.Notification) newNotifer, err := InsertDatabase(u.Notification)
if err != nil { if err != nil {
@ -188,5 +188,5 @@ func (u *Twilio) Install() error {
} }
utils.Log(1, fmt.Sprintf("new notifier #%v installed: %v", newNotifer, u.Method)) utils.Log(1, fmt.Sprintf("new notifier #%v installed: %v", newNotifer, u.Method))
} }
return err return nil
} }

View File

@ -10,21 +10,20 @@ CREATE TABLE core (
version VARCHAR(50), version VARCHAR(50),
migration_id INT(6) NOT NULL DEFAULT 0, migration_id INT(6) NOT NULL DEFAULT 0,
use_cdn BOOL NOT NULL DEFAULT '0' use_cdn BOOL NOT NULL DEFAULT '0'
); ) ENGINE=INNODB;
CREATE TABLE users ( CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id),
username VARCHAR(50) NOT NULL UNIQUE, username VARCHAR(50) NOT NULL UNIQUE,
password text, password text,
email VARCHAR (50), email VARCHAR (50),
api_key VARCHAR(50), api_key VARCHAR(50),
api_secret VARCHAR(50), api_secret VARCHAR(50),
administrator BOOL NOT NULL DEFAULT '0', administrator BOOL NOT NULL DEFAULT '0',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX (id),
UNIQUE (username, email) UNIQUE (username, email)
); ) ENGINE=INNODB;
CREATE TABLE services ( CREATE TABLE services (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id),
name VARCHAR(50), name VARCHAR(50),
domain text, domain text,
check_type text, check_type text,
@ -35,38 +34,34 @@ CREATE TABLE services (
check_interval int(11), check_interval int(11),
post_data text, post_data text,
order_id integer default 0, order_id integer default 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
timeout INT(6) DEFAULT 30, timeout INT(6) DEFAULT 30
INDEX (id) ) ENGINE=INNODB;
);
CREATE TABLE hits ( CREATE TABLE hits (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id),
service INTEGER NOT NULL, service BIGINT(20) UNSIGNED NOT NULL,
latency float, latency float,
created_at DATETIME, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX (id, service),
FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
); ) ENGINE=INNODB;
CREATE TABLE failures ( CREATE TABLE failures (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id),
issue text, issue text,
method text, method text,
service INTEGER NOT NULL, service BIGINT(20) UNSIGNED NOT NULL,
created_at DATETIME, created_at TIMESTAMP,
INDEX (id, service),
FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
); ) ENGINE=INNODB;
CREATE TABLE checkins ( CREATE TABLE checkins (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id),
service INTEGER NOT NULL, service BIGINT(20) UNSIGNED NOT NULL,
check_interval integer, check_interval integer,
api text, api text,
created_at DATETIME, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX (id, service),
FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
); ) ENGINE=INNODB;
CREATE TABLE communication ( CREATE TABLE communication (
id SERIAL PRIMARY KEY, id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(id),
method text, method text,
host text, host text,
port integer, port integer,
@ -79,5 +74,5 @@ CREATE TABLE communication (
enabled BOOL NOT NULL DEFAULT '0', enabled BOOL NOT NULL DEFAULT '0',
removable BOOL NOT NULL DEFAULT '0', removable BOOL NOT NULL DEFAULT '0',
limits integer, limits integer,
created_at DATETIME created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
); ) ENGINE=INNODB;

View File

@ -11,21 +11,19 @@ CREATE TABLE core (
migration_id integer default 0, migration_id integer default 0,
use_cdn bool default false use_cdn bool default false
); );
CREATE TABLE users ( CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY,
username text NOT NULL UNIQUE, username text NOT NULL UNIQUE,
password text, password text,
email text, email text,
api_key text, api_key text,
api_secret text, api_secret text,
administrator bool, administrator bool,
created_at DATETIME, created_at TIMESTAMP,
UNIQUE (username, email) UNIQUE (username, email)
); );
CREATE TABLE services ( CREATE TABLE services (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY,
name text, name text,
domain text, domain text,
check_type text, check_type text,
@ -37,34 +35,34 @@ CREATE TABLE services (
post_data text, post_data text,
order_id integer default 0, order_id integer default 0,
timeout integer default 30, timeout integer default 30,
created_at DATETIME created_at TIMESTAMP
); );
CREATE TABLE hits ( CREATE TABLE hits (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY,
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE, service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
latency float, latency float,
created_at DATETIME created_at TIMESTAMP
); );
CREATE TABLE failures ( CREATE TABLE failures (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY,
issue text, issue text,
method text, method text,
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE, service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
created_at DATETIME created_at TIMESTAMP
); );
CREATE TABLE checkins ( CREATE TABLE checkins (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY,
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE, service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
check_interval integer, check_interval integer,
api text, api text,
created_at DATETIME created_at TIMESTAMP
); );
CREATE TABLE communication ( CREATE TABLE communication (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY,
method text, method text,
host text, host text,
port integer, port integer,
@ -77,7 +75,7 @@ CREATE TABLE communication (
enabled boolean, enabled boolean,
removable boolean, removable boolean,
limits integer, limits integer,
created_at DATETIME created_at TIMESTAMP
); );

View File

@ -73,14 +73,14 @@
Average Response Average Response
</div> </div>
<div class="col-4"> <div class="col-4">
<span class="lg_number">{{.AvgUptime}}%</span> <span class="lg_number">{{.AvgUptime24}}%</span>
Total Uptime Uptime last 24 Hours
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{{ if .AvgTime }} {{ if .AvgUptime24 }}
<div class="chart-container"> <div class="chart-container">
<canvas id="service_{{ .Id }}"></canvas> <canvas id="service_{{ .Id }}"></canvas>
</div> </div>

View File

@ -51,7 +51,7 @@
</div> </div>
<div class="col-4"> <div class="col-4">
<span class="lg_number">{{.AvgUptime}}%</span> <span class="lg_number">{{.AvgUptime24}}%</span>
Total Uptime Total Uptime
</div> </div>
</div> </div>

View File

@ -1,13 +1,15 @@
package types package types
import "time" import (
"time"
)
type Checkin struct { type Checkin struct {
Id int `db:"id,omitempty"` Id int64 `gorm:"primary_key;column:id"`
Service int64 `db:"service"` Service int64 `gorm:"index;column:service"`
Interval int64 `db:"check_interval"` Interval int64 `gorm:"column:check_interval"`
Api string `db:"api"` Api string `gorm:"column:api"`
CreatedAt time.Time `db:"created_at"` CreatedAt time.Time `gorm:"column:created_at"`
Hits int64 `json:"hits"` Hits int64 `json:"hits"`
Last time.Time `json:"last"` Last time.Time `json:"last"`
CheckinInterface `json:"-"` CheckinInterface `json:"-"`

View File

@ -1,27 +1,29 @@
package types package types
import "time" import (
"time"
)
type Core struct { type Core struct {
Name string `db:"name" json:"name"` Name string `gorm:"column:name" json:"name"`
Description string `db:"description" json:"description,omitempty"` Description string `gorm:"column:description" json:"description,omitempty"`
Config string `db:"config" json:"-"` Config string `gorm:"column:config" json:"-"`
ApiKey string `db:"api_key" json:"-"` ApiKey string `gorm:"column:api_key" json:"-"`
ApiSecret string `db:"api_secret" json:"-"` ApiSecret string `gorm:"column:api_secret" json:"-"`
Style string `db:"style" json:"style,omitempty"` Style string `gorm:"column:style" json:"style,omitempty"`
Footer string `db:"footer" json:"footer,omitempty"` Footer string `gorm:"column:footer" json:"footer,omitempty"`
Domain string `db:"domain" json:"domain,omitempty"` Domain string `gorm:"column:domain" json:"domain,omitempty"`
Version string `db:"version" json:"version"` Version string `gorm:"column:version" json:"version"`
MigrationId int64 `db:"migration_id" json:"migration_id,omitempty"` MigrationId int64 `gorm:"column:migration_id" json:"migration_id,omitempty"`
UseCdn bool `db:"use_cdn" json:"using_cdn,omitempty"` UseCdn bool `gorm:"column:use_cdn" json:"using_cdn,omitempty"`
DbConnection string `json:"database"` DbConnection string `gorm:"-" json:database"`
Started time.Time `json:"started_on"` Started time.Time `gorm:"-" json:started_on"`
dbServices []*Service `json:"services,omitempty"` dbServices []*Service `gorm:"-" json:services,omitempty"`
Plugins []Info `json:"-"` Plugins []Info `gorm:"-" json:-"`
Repos []PluginJSON `json:"-"` Repos []PluginJSON `gorm:"-" json:-"`
AllPlugins []PluginActions `json:"-"` AllPlugins []PluginActions `gorm:"-" json:-"`
Communications []AllNotifiers `json:"-"` Communications []AllNotifiers `gorm:"-" json:-"`
CoreInterface `json:"-"` CoreInterface `gorm:"-" json:-"`
} }
func (c *Core) SetServices(s []*Service) { func (c *Core) SetServices(s []*Service) {

View File

@ -1,14 +1,16 @@
package types package types
import "time" import (
"time"
)
type Failure struct { type Failure struct {
Id int `db:"id,omitempty" json:"id"` Id int64 `gorm:"primary_key;column:id" json:"id"`
Issue string `db:"issue" json:"issue"` Issue string `gorm:"column:issue" json:"issue"`
Method string `db:"method" json:"method,omitempty"` Method string `gorm:"column:method" json:"method,omitempty"`
Service int64 `db:"service" json:"service_id"` Service int64 `gorm:"index;column:service" json:"service_id"`
CreatedAt time.Time `db:"created_at" json:"created_at"` CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
FailureInterface `json:"-"` FailureInterface `gorm:"-" json:"-"`
} }
type FailureInterface interface { type FailureInterface interface {

View File

@ -20,33 +20,33 @@ import (
) )
type Service struct { type Service struct {
Id int64 `db:"id,omitempty" json:"id"` Id int64 `gorm:"primary_key;column:id" json:"id"`
Name string `db:"name" json:"name"` Name string `gorm:"column:name" json:"name"`
Domain string `db:"domain" json:"domain"` Domain string `gorm:"column:domain" json:"domain"`
Expected string `db:"expected" json:"expected"` Expected string `gorm:"column:expected" json:"expected"`
ExpectedStatus int `db:"expected_status" json:"expected_status"` ExpectedStatus int `gorm:"column:expected_status" json:"expected_status"`
Interval int `db:"check_interval" json:"check_interval"` Interval int `gorm:"column:check_interval" json:"check_interval"`
Type string `db:"check_type" json:"type"` Type string `gorm:"column:check_type" json:"type"`
Method string `db:"method" json:"method"` Method string `gorm:"column:method" json:"method"`
PostData string `db:"post_data" json:"post_data"` PostData string `gorm:"column:post_data" json:"post_data"`
Port int `db:"port" json:"port"` Port int `gorm:"column:port" json:"port"`
CreatedAt time.Time `db:"created_at" json:"created_at"` CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
Timeout int `db:"timeout" json:"timeout"` Timeout int `gorm:"column:timeout" json:"timeout"`
Order int `db:"order_id" json:"order_id"` Order int `gorm:"column:order_id" json:"order_id"`
Online bool `json:"online"` Online bool `gorm:"-" json:"online"`
Latency float64 `json:"latency"` Latency float64 `gorm:"-" json:"latency"`
Online24Hours float32 `json:"24_hours_online"` Online24Hours float32 `gorm:"-" json:"24_hours_online"`
AvgResponse string `json:"avg_response"` AvgResponse string `gorm:"-" json:"avg_response"`
TotalUptime string `json:"uptime"` TotalUptime string `gorm:"-" json:"uptime"`
Failures []*Failure `json:"failures"` Failures []*Failure `gorm:"-" json:"failures"`
Checkins []*Checkin `json:"checkins"` Checkins []*Checkin `gorm:"-" json:"checkins"`
Running chan bool `json:"-"` Running chan bool `gorm:"-" json:"-"`
Checkpoint time.Time `json:"-"` Checkpoint time.Time `gorm:"-" json:"-"`
LastResponse string `json:"-"` LastResponse string `gorm:"-" json:"-"`
LastStatusCode int `json:"status_code"` LastStatusCode int `gorm:"-" json:"status_code"`
LastOnline time.Time `json:"last_online"` LastOnline time.Time `gorm:"-" json:"last_online"`
DnsLookup float64 `json:"dns_lookup_time"` DnsLookup float64 `gorm:"-" json:"dns_lookup_time"`
ServiceInterface `json:"-"` ServiceInterface `gorm:"-" json:"-"`
} }
type ServiceInterface interface { type ServiceInterface interface {
@ -56,6 +56,7 @@ type ServiceInterface interface {
Delete() error Delete() error
// Basic Method functions // Basic Method functions
AvgTime() float64 AvgTime() float64
OnlineSince(time.Time) float32
Online24() float32 Online24() float32
SmallText() string SmallText() string
GraphData() string GraphData() string
@ -65,13 +66,15 @@ type ServiceInterface interface {
CreateFailure(*Failure) (int64, error) CreateFailure(*Failure) (int64, error)
LimitedFailures() []*Failure LimitedFailures() []*Failure
AllFailures() []*Failure AllFailures() []*Failure
TotalFailuresSince(time.Time) (uint64, error)
TotalFailures24() (uint64, error)
TotalFailures() (uint64, error) TotalFailures() (uint64, error)
TotalFailures24Hours() (uint64, error)
DeleteFailures() DeleteFailures()
// Hits functions (successful responses) // Hits functions (successful responses)
CreateHit(*Hit) (int64, error) CreateHit(*Hit) (int64, error)
Hits() ([]*Hit, error) Hits() ([]*Hit, error)
TotalHits() (uint64, error) TotalHits() (uint64, error)
TotalHitsSince(time.Time) (uint64, error)
Sum() (float64, error) Sum() (float64, error)
LimitedHits() ([]*Hit, error) LimitedHits() ([]*Hit, error)
SelectHitsGroupBy(string) ([]*Hit, error) SelectHitsGroupBy(string) ([]*Hit, error)

View File

@ -16,9 +16,9 @@
package types package types
import ( import (
"github.com/jinzhu/gorm"
"net/http" "net/http"
"time" "time"
"upper.io/db.v3/lib/sqlbuilder"
) )
type PluginInfo struct { type PluginInfo struct {
@ -41,7 +41,7 @@ type Info struct {
type PluginActions interface { type PluginActions interface {
GetInfo() Info GetInfo() Info
GetForm() string GetForm() string
OnLoad(sqlbuilder.Database) OnLoad(db gorm.DB)
SetInfo(map[string]interface{}) Info SetInfo(map[string]interface{}) Info
Routes() []Routing Routes() []Routing
OnSave(map[string]interface{}) OnSave(map[string]interface{})
@ -62,20 +62,10 @@ type PluginActions interface {
type AllNotifiers interface{} type AllNotifiers interface{}
type Hit struct { type Hit struct {
Id int `db:"id,omitempty"` Id int64 `gorm:"primary_key;column:id"`
Service int64 `db:"service"` Service int64 `gorm:"index;column:service"`
Latency float64 `db:"latency"` Latency float64 `gorm:"column:latency"`
CreatedAt time.Time `db:"created_at"` CreatedAt time.Time `gorm:"column:created_at"`
}
type Config struct {
Connection string `yaml:"connection"`
Host string `yaml:"host"`
Database string `yaml:"database"`
User string `yaml:"user"`
Password string `yaml:"password"`
Port string `yaml:"port"`
Secret string `yaml:"secret"`
} }
type DbConfig struct { type DbConfig struct {

View File

@ -1,17 +1,19 @@
package types package types
import "time" import (
"time"
)
type User struct { type User struct {
Id int64 `db:"id,omitempty" json:"id"` Id int64 `gorm:"primary_key;column:id" json:"id"`
Username string `db:"username" json:"username"` Username string `gorm:"type:varchar(100);unique;column:username;" json:"username"`
Password string `db:"password" json:"-"` Password string `gorm:"column:password" json:"-"`
Email string `db:"email" json:"-"` Email string `gorm:"type:varchar(100);unique;column:email" json:"-"`
ApiKey string `db:"api_key" json:"api_key"` ApiKey string `gorm:"column:api_key" json:"api_key"`
ApiSecret string `db:"api_secret" json:"-"` ApiSecret string `gorm:"column:api_secret" json:"-"`
Admin bool `db:"administrator" json:"admin"` Admin bool `gorm:"column:administrator" json:"admin"`
CreatedAt time.Time `db:"created_at" json:"created_at"` CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
UserInterface `json:"-"` UserInterface `gorm:"-" json:"-"`
} }
type UserInterface interface { type UserInterface interface {

View File

@ -34,6 +34,10 @@ var (
LockLines sync.Mutex LockLines sync.Mutex
) )
func Logger() *lumberjack.Logger {
return ljLogger
}
func createLog(dir string) error { func createLog(dir string) error {
var err error var err error
_, err = os.Stat(dir + "/logs") _, err = os.Stat(dir + "/logs")

View File

@ -16,8 +16,11 @@
package utils package utils
import ( import (
"errors"
"github.com/ararog/timeago" "github.com/ararog/timeago"
"io"
"os" "os"
"os/exec"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@ -97,6 +100,7 @@ func FileExists(name string) bool {
} }
func DeleteFile(file string) error { func DeleteFile(file string) error {
Log(1, "deleting file: "+file)
err := os.Remove(file) err := os.Remove(file)
if err != nil { if err != nil {
return err return err
@ -107,3 +111,56 @@ func DeleteFile(file string) error {
func DeleteDirectory(directory string) error { func DeleteDirectory(directory string) error {
return os.RemoveAll(directory) return os.RemoveAll(directory)
} }
func Command(cmd string) (string, string, error) {
Log(1, "running command: "+cmd)
testCmd := exec.Command("sh", "-c", cmd)
var stdout, stderr []byte
var errStdout, errStderr error
stdoutIn, _ := testCmd.StdoutPipe()
stderrIn, _ := testCmd.StderrPipe()
testCmd.Start()
go func() {
stdout, errStdout = copyAndCapture(os.Stdout, stdoutIn)
}()
go func() {
stderr, errStderr = copyAndCapture(os.Stderr, stderrIn)
}()
err := testCmd.Wait()
if err != nil {
return "", "", err
}
if errStdout != nil || errStderr != nil {
return "", "", errors.New("failed to capture stdout or stderr")
}
outStr, errStr := string(stdout), string(stderr)
return outStr, errStr, err
}
func copyAndCapture(w io.Writer, r io.Reader) ([]byte, error) {
var out []byte
buf := make([]byte, 1024, 1024)
for {
n, err := r.Read(buf[:])
if n > 0 {
d := buf[:n]
out = append(out, d...)
_, err := w.Write(d)
if err != nil {
return out, err
}
}
if err != nil {
// Read returns io.EOF at the end of file, which is not an error for us
if err == io.EOF {
err = nil
}
return out, err
}
}
}