Merge branch 'master' into line-notify

pull/61/head
Hunter Long 2018-09-06 13:04:08 -07:00 committed by GitHub
commit 82f2c47c8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 1540 additions and 1097 deletions

View File

@ -4,7 +4,7 @@ os:
language: go
go:
- "1.10.x"
- "1.10.3"
go_import_path: github.com/hunterlong/statup

222
Gopkg.lock generated
View File

@ -1,6 +1,14 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:b62a3c5b37db602bf1158e921da1a762315a4c37855fd418a14498aa87a342d5"
name = "cloud.google.com/go"
packages = ["civil"]
pruneopts = "UT"
revision = "c728a003b238b26cef9ab6753a5dc424b331c3ad"
version = "v0.27.0"
[[projects]]
branch = "master"
digest = "1:65796e5fdb94d94bc0ee6bc422aa3541dbe69ed4da275cb5a27f8fa141f4e35c"
@ -13,12 +21,20 @@
revision = "c02ca9a983da5807ddf7d796784928f5be4afd09"
[[projects]]
branch = "master"
digest = "1:4b79025e1eaa5726b92e409a46571f1998b56f0a2d881d6271ca616095eae46e"
digest = "1:e92f5581902c345eb4ceffdcd4a854fb8f73cf436d47d837d1ec98ef1fe0a214"
name = "github.com/StackExchange/wmi"
packages = ["."]
pruneopts = "UT"
revision = "5d049714c4a64225c3c79a7cf7d02f7fb5b96338"
version = "1.0.0"
[[projects]]
digest = "1:f1ec92a2b8473612547f6e13edbc8c8e6cda6c8be9c54b31958aad4a7ccaaa2b"
name = "github.com/ararog/timeago"
packages = ["."]
pruneopts = "UT"
revision = "e9969cf18b8d5f04cc42f050e8b9968e152cd294"
revision = "518814407569bf983ea81e1bf8b550dd4e7b34f3"
version = "0.0.1"
[[projects]]
branch = "master"
@ -29,28 +45,50 @@
revision = "a5fe2436ffcb3236e175e5149162b41cd28bd27d"
[[projects]]
digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
name = "github.com/davecgh/go-spew"
packages = ["spew"]
pruneopts = "UT"
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
version = "v1.1.1"
[[projects]]
branch = "master"
digest = "1:14f498fc55a89776c562fa3510aeb7687356944a560c561c0e617af5f9c5f2c7"
digest = "1:6f120164f62e62991d0f85562abe2002d438abb2ca80b7717a2f4ae2af1c6829"
name = "github.com/denisenkom/go-mssqldb"
packages = [
".",
"internal/cp",
]
pruneopts = "UT"
revision = "1eb28afdf9b6e56cf673badd47545f844fe81103"
[[projects]]
digest = "1:ca82a3b99694824c627573c2a76d0e49719b4a9c02d1d85a2ac91f1c1f52ab9b"
name = "github.com/fatih/structs"
packages = ["."]
pruneopts = "UT"
revision = "ebf56d35bba727c68ac77f56f2fcf90b181851aa"
revision = "a720dfa8df582c51dee1b36feabb906bde1588bd"
version = "v1.0"
[[projects]]
branch = "master"
digest = "1:70a20b8adf085489a342d033b68b7fc27f4017c51e015b857387249493ee0561"
digest = "1:64a5a67c69b70c2420e607a8545d674a23778ed9c3e80607bfd17b77c6c87f6a"
name = "github.com/go-ole/go-ole"
packages = [
".",
"oleutil",
]
pruneopts = "UT"
revision = "a41e3c4b706f6ae8dfbff342b06e40fa4d2d0506"
version = "v1.2.1"
[[projects]]
digest = "1:adea5a94903eb4384abef30f3d878dc9ff6b6b5b0722da25b82e5169216dfb61"
name = "github.com/go-sql-driver/mysql"
packages = ["."]
pruneopts = "UT"
revision = "99ff426eb706cffe92ff3d058e168b278cabf7c7"
revision = "d523deb1b23d913de5bdada721a6071e71283618"
version = "v1.4.0"
[[projects]]
digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
@ -69,35 +107,74 @@
version = "v1.1.1"
[[projects]]
digest = "1:195b71563f8432dac9d9692aca2a9ae098bc35763999573eb1c7d52a02a47ce7"
digest = "1:664d37ea261f0fc73dd17f4a1f5f46d01fbb0b0d75f6375af064824424109b7d"
name = "github.com/gorilla/handlers"
packages = ["."]
pruneopts = "UT"
revision = "7e0847f9db758cdebd26c149d0ae9d5d0b9c98ce"
version = "v1.4.0"
[[projects]]
digest = "1:e73f5b0152105f18bc131fba127d9949305c8693f8a762588a82a48f61756f5f"
name = "github.com/gorilla/mux"
packages = ["."]
pruneopts = "UT"
revision = "cb4698366aa625048f3b815af6a0dea8aef9280a"
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
version = "v1.6.2"
[[projects]]
branch = "master"
digest = "1:6e0af49591c81ae6d542fd0ba41ea7206f4242471b384bebd206283b9f38e091"
digest = "1:e72d1ebb8d395cf9f346fd9cbc652e5ae222dd85e0ac842dc57f175abed6d195"
name = "github.com/gorilla/securecookie"
packages = ["."]
pruneopts = "UT"
revision = "78f3d318a8bf316cda921f25e96fd0b441c5173d"
[[projects]]
digest = "1:0fe783ea0c04c7d13f7c55d8f74b01b17e18a8320e7deecf578b41ef99b27205"
name = "github.com/gorilla/sessions"
packages = ["."]
pruneopts = "UT"
revision = "03b6f63cc43ef9c7240a635a5e22b13180e822b8"
revision = "e59506cc896acb7f7bf732d4fdf5e25f7ccd8983"
version = "v1.1.1"
[[projects]]
digest = "1:0aa142ca3543fa3aca344c2fa2d52e01d706a3ce4e1fa893e0ef29b5349ddf7a"
name = "github.com/gorilla/sessions"
packages = ["."]
pruneopts = "UT"
revision = "81547393f870a35be888759a606ba7bf71dbe5c7"
version = "v1.1.2"
[[projects]]
digest = "1:7b5c6e2eeaa9ae5907c391a91c132abfd5c9e8a784a341b5625e750c67e6825d"
name = "github.com/gorilla/websocket"
packages = ["."]
pruneopts = "UT"
revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d"
version = "v1.4.0"
[[projects]]
digest = "1:4d28d632da146ec6e632bdd29676a95e0874f1ad837fff06aef6610b3b6b4728"
name = "github.com/jinzhu/gorm"
packages = [
".",
"dialects/mssql",
"dialects/mysql",
"dialects/postgres",
"dialects/sqlite",
]
pruneopts = "UT"
revision = "6ed508ec6a4ecb3531899a69cbc746ccf65a4166"
version = "v1.9.1"
[[projects]]
branch = "master"
digest = "1:d166a4b3543a71d87e34767ace94e8b516e79ba45111730306f07c8d6f797f1f"
digest = "1:fd97437fbb6b7dce04132cf06775bd258cce305c44add58eb55ca86c6c325160"
name = "github.com/jinzhu/inflection"
packages = ["."]
pruneopts = "UT"
revision = "04140366298a54a039076d798123ffa108fff46c"
[[projects]]
digest = "1:70e697d67ccaec45e16bac3a32380ebcd9e7e071079c60d0171d42cf1cf9748a"
name = "github.com/joho/godotenv"
packages = ["."]
pruneopts = "UT"
revision = "1709ab122c988931ad53508747b3c061400c2984"
revision = "a79fa1e548e2c689c241d10173efd51e5d689d5b"
version = "v1.2.0"
[[projects]]
branch = "master"
@ -108,31 +185,43 @@
revision = "ae77be60afb1dcacde03767a8c37337fad28ac14"
[[projects]]
branch = "master"
digest = "1:37ce7d7d80531b227023331002c0d42b4b4b291a96798c82a049d03a54ba79e4"
digest = "1:b18ffc558326ebaed3b4a175617f1e12ed4e3f53d6ebfe5ba372a3de16d22278"
name = "github.com/lib/pq"
packages = [
".",
"hstore",
"oid",
]
pruneopts = "UT"
revision = "90697d60dd844d5ef6ff15135d0203f65d2f53b8"
revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:05b7bf6e275fe5d56f479a944d1fd823437f6a2739610ae8359e137690d0a050"
digest = "1:3cafc6a5a1b8269605d9df4c6956d43d8011fc57f266ca6b9d04da6c09dee548"
name = "github.com/mattn/go-sqlite3"
packages = ["."]
pruneopts = "UT"
revision = "b3511bfdd742af558b54eb6160aca9446d762a19"
revision = "25ecb14adfc7543176f7d85291ec7dba82c6f7e4"
version = "v1.9.0"
[[projects]]
branch = "master"
digest = "1:3891cc78541df6e4596b3e73978eb062d32967084069270ec881b959be5155ae"
digest = "1:4f4fd75cbdd5ad0696f4d762328f094b9c86061323c9a9f8d0de157f06197e89"
name = "github.com/mkevac/debugcharts"
packages = [
".",
"bindata",
]
pruneopts = "UT"
revision = "d3203a8fa92649b82dc35c214979861de918874a"
[[projects]]
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
name = "github.com/pkg/errors"
packages = ["."]
pruneopts = "UT"
revision = "816c9085562cd7ee03e7f8188a1cfd942858cded"
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
@ -150,6 +239,29 @@
pruneopts = "UT"
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]]
digest = "1:18752d0b95816a1b777505a97f71c7467a8445b8ffb55631a7bf779f6ba4fa83"
name = "github.com/stretchr/testify"
@ -159,14 +271,27 @@
version = "v1.2.2"
[[projects]]
digest = "1:1ecf2a49df33be51e757d0033d5d51d5f784f35f68e5a38f797b2d3f03357d71"
branch = "master"
digest = "1:68344dbfaa4179bb50a583eb8172ace3f1edaf3aebc24e68c03f549f6e6b60dc"
name = "golang.org/x/crypto"
packages = [
"bcrypt",
"blowfish",
"md4",
]
pruneopts = "UT"
revision = "c126467f60eb25f8f27e5a981f32a87e3965053f"
revision = "0709b304e793a5edb4a2c0145f281ecdc20838a4"
[[projects]]
branch = "master"
digest = "1:7f4a61b989d94774dc61016b660cf8347f59eb0bed91a10b2f23fc72a38d45d4"
name = "golang.org/x/sys"
packages = [
"unix",
"windows",
]
pruneopts = "UT"
revision = "ebe1bf3edb3325c393447059974de898d5133eb8"
[[projects]]
digest = "1:c25289f43ac4a68d88b02245742347c94f1e108c534dda442188015ff80669b3"
@ -185,12 +310,12 @@
revision = "2caba252f4dc53eaf6b553000885530023f54623"
[[projects]]
branch = "v2"
digest = "1:e096ada745e034a059752c202717baee0379b69db9473a90f59d103c973384cf"
digest = "1:eebd52aee67d9f1e0af1859a584e14b1817581dd5f90d4585418c27b6a93c966"
name = "gopkg.in/gomail.v2"
packages = ["."]
pruneopts = "UT"
revision = "81ebce5c23dfd25c6c67194b37d3dd3f338c98b1"
revision = "41f3572897373c5538c50a2402db15db079fa4fd"
version = "2.0.0"
[[projects]]
digest = "1:c805e517269b0ba4c21ded5836019ed7d16953d4026cb7d00041d039c7906be9"
@ -201,25 +326,21 @@
version = "v2.1"
[[projects]]
digest = "1:0d1f3aba6c5c26e67b090b4eed519582fba0dff24d3e486fcb011d84ca3e7806"
digest = "1:0a6ab450a46e158a97e3daf7da9df3bfd4f84420047fab6a65fb70b1337ce026"
name = "upper.io/db.v3"
packages = [
".",
"internal/cache",
"internal/cache/hashstructure",
"internal/immutable",
"internal/sqladapter",
"internal/sqladapter/compat",
"internal/sqladapter/exql",
"lib/reflectx",
"lib/sqlbuilder",
"mysql",
"postgresql",
"sqlite",
]
pruneopts = "UT"
revision = "d90922beee6de3f39c93ed677f6da82565d07154"
version = "v3.5.3"
revision = "199d13d76c7cfba05ea0327375056fdabc8bea80"
version = "v3.5.4"
[solve-meta]
analyzer-name = "dep"
@ -230,20 +351,23 @@
"github.com/ararog/timeago",
"github.com/fatih/structs",
"github.com/go-yaml/yaml",
"github.com/gorilla/handlers",
"github.com/gorilla/mux",
"github.com/gorilla/sessions",
"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/joho/godotenv",
"github.com/mkevac/debugcharts",
"github.com/pkg/errors",
"github.com/rendon/testcli",
"github.com/stretchr/testify/assert",
"golang.org/x/crypto/bcrypt",
"gopkg.in/gomail.v2",
"gopkg.in/natefinch/lumberjack.v2",
"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",
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -30,28 +30,44 @@
name = "github.com/GeertJohan/go.rice"
[[constraint]]
branch = "master"
name = "github.com/ararog/timeago"
version = "0.0.1"
[[constraint]]
branch = "master"
name = "github.com/fatih/structs"
version = "1.0.0"
[[constraint]]
name = "github.com/go-yaml/yaml"
version = "2.2.1"
[[constraint]]
name = "github.com/gorilla/handlers"
version = "1.4.0"
[[constraint]]
name = "github.com/gorilla/mux"
version = "1.6.2"
[[constraint]]
name = "github.com/gorilla/sessions"
version = "1.1.1"
version = "1.1.2"
[[constraint]]
name = "github.com/jinzhu/gorm"
version = "1.9.1"
[[constraint]]
branch = "master"
name = "github.com/joho/godotenv"
version = "1.2.0"
[[constraint]]
branch = "master"
name = "github.com/mkevac/debugcharts"
[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"
[[constraint]]
branch = "master"
@ -62,8 +78,12 @@
version = "1.2.2"
[[constraint]]
branch = "v2"
branch = "master"
name = "golang.org/x/crypto"
[[constraint]]
name = "gopkg.in/gomail.v2"
version = "2.0.0"
[[constraint]]
name = "gopkg.in/natefinch/lumberjack.v2"
@ -71,7 +91,7 @@
[[constraint]]
name = "upper.io/db.v3"
version = "3.5.3"
version = "3.5.4"
[prune]
go-tests = true

View File

@ -1,4 +1,4 @@
VERSION=0.52
VERSION=0.54
BINARY_NAME=statup
GOPATH:=$(GOPATH)
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
seed:
rm -f statup.db
cat dev/seed.sql | sqlite3 statup.db
build: compile
$(GOBUILD) $(BUILDVERSION) -o $(BINARY_NAME) -v ./cmd
@ -127,6 +131,7 @@ dep:
dep ensure -vendor-only
dev-deps: dep
$(GOGET) -u github.com/jinzhu/gorm/...
$(GOGET) github.com/stretchr/testify/assert
$(GOGET) golang.org/x/tools/cmd/cover
$(GOGET) github.com/mattn/goveralls

View File

@ -24,13 +24,12 @@ import (
"github.com/hunterlong/statup/source"
"github.com/hunterlong/statup/types"
"github.com/hunterlong/statup/utils"
"github.com/jinzhu/gorm"
"github.com/joho/godotenv"
"io/ioutil"
"math/rand"
"net/http"
"strings"
"time"
"upper.io/db.v3/sqlite"
)
const (
@ -45,6 +44,8 @@ func CatchCLI(args []string) error {
LoadDotEnvs()
switch args[0] {
case "seed":
handlers.DesktopInit(ipAddress, port)
case "app":
handlers.DesktopInit(ipAddress, port)
case "version":
@ -94,7 +95,7 @@ func CatchCLI(args []string) error {
case "export":
var err error
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 {
utils.Log(4, "config.yml file not found")
return err
@ -132,11 +133,11 @@ func CatchCLI(args []string) error {
func RunOnce() {
var err error
core.Configs, err = core.LoadConfig()
core.Configs, err = core.LoadConfig(utils.Directory)
if err != nil {
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 {
utils.Log(4, err)
}
@ -234,21 +235,10 @@ func FakeSeed(plug types.PluginActions) {
fmt.Printf("\n" + BRAKER)
fmt.Println("\nCreating a SQLite database for testing, will be deleted automatically...")
sqlFake := sqlite.ConnectionURL{
Database: "./.plugin_test.db",
}
core.DbSession, err = sqlite.Open(sqlFake)
core.DbSession, err = gorm.Open("sqlite", "./.plugin_test.db")
if err != nil {
utils.Log(3, err)
}
up, _ := source.SqlBox.String("sqlite_up.sql")
requests := strings.Split(up, ";")
for _, request := range requests {
_, err := core.DbSession.Exec(request)
if err != nil {
utils.Log(2, err)
}
}
fmt.Println("Finished creating Test SQLite database")
fmt.Println("Inserting example services into test database...")

View File

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

View File

@ -31,27 +31,30 @@ import (
"os"
"strings"
"testing"
"time"
)
var (
route *mux.Router
testSession *sessions.Session
dir string
route *mux.Router
testSession *sessions.Session
dir string
SERVICE_SINCE, _ = time.Parse(time.RFC3339, "2018-08-30T10:42:08-07:00")
)
func init() {
dir = utils.Directory
os.Remove(dir + "/statup.db")
//os.Remove(gopath+"/cmd/config.yml")
os.RemoveAll(dir + "/cmd/assets")
os.RemoveAll(dir + "/logs")
}
func Clean() {
utils.DeleteFile(dir + "/config.yml")
utils.DeleteFile(dir + "/statup.db")
utils.DeleteDirectory(dir + "/assets")
utils.DeleteDirectory(dir + "/logs")
}
func RunInit(t *testing.T) {
source.Assets()
os.Remove(dir + "/statup.db")
os.Remove(dir + "/cmd/config.yml")
os.Remove(dir + "/cmd/index.html")
Clean()
route = handlers.Router()
LoadDotEnvs()
core.CoreApp = core.NewCore()
@ -60,35 +63,55 @@ func RunInit(t *testing.T) {
func TestRunAll(t *testing.T) {
//t.Parallel()
databases := []string{"sqlite", "postgres", "mysql"}
databases := []string{"postgres", "sqlite", "mysql"}
if os.Getenv("ONLY_DB") != "" {
databases = []string{os.Getenv("ONLY_DB")}
}
for _, dbt := range databases {
t.Run(dbt+" init", func(t *testing.T) {
RunInit(t)
})
t.Run(dbt+" load database config", func(t *testing.T) {
RunMakeDatabaseConfig(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+" Save Config", func(t *testing.T) {
RunSaveConfig(t, dbt)
})
t.Run(dbt+" Load Configs", func(t *testing.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) {
RunDatabaseMigrations(t, dbt)
})
t.Run(dbt+" Select Core", func(t *testing.T) {
RunSelectCoreMYQL(t, dbt)
t.Log(core.CoreApp)
})
t.Run(dbt+" Select Services", func(t *testing.T) {
RunSelectAllMysqlServices(t)
})
t.Run(dbt+" Select Comms", func(t *testing.T) {
t.SkipNow()
RunSelectAllMysqlCommunications(t)
})
t.Run(dbt+" Create Users", func(t *testing.T) {
@ -131,7 +154,7 @@ func TestRunAll(t *testing.T) {
t.Run(dbt+" Create Failing Service", func(t *testing.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)
})
t.Run(dbt+" Select Hits", func(t *testing.T) {
@ -183,35 +206,24 @@ func TestRunAll(t *testing.T) {
RunSettingsHandler(t)
})
t.Run(dbt+" Cleanup", func(t *testing.T) {
//Cleanup(t)
core.Configs.Close()
core.DbSession = nil
//Clean()
})
//<-done
}
}
func Cleanup(t *testing.T) {
core.DbSession.ClearCache()
err := core.DbSession.Close()
assert.Nil(t, err)
}
func RunMakeDatabaseConfig(t *testing.T, db string) {
func RunSaveConfig(t *testing.T, db string) {
var err error
port := 5432
if db == "mysql" {
port = 3306
}
//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{
core.Configs = &core.DbConfig{DbConfig: &types.DbConfig{
DbConn: db,
DbHost: os.Getenv("DB_HOST"),
DbUser: os.Getenv("DB_USER"),
@ -227,39 +239,49 @@ func RunMakeDatabaseConfig(t *testing.T, db string) {
Error: nil,
Location: dir,
}}
err := config.Save()
core.Configs, err = core.Configs.Save()
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.Equal(t, db, core.Configs.Connection)
err = core.DbConnection(core.Configs.Connection, false, dir)
err = core.Configs.CreateDatabase()
assert.Nil(t, err)
}
func RunDatabaseMigrations(t *testing.T, db string) {
err := core.RunDatabaseUpgrades()
err := core.Configs.MigrateDatabase()
assert.Nil(t, err)
}
func RunInsertSampleData(t *testing.T) {
err := core.LoadSampleData()
assert.Nil(t, err)
core.Configs.SeedDatabase()
//assert.Nil(t, err)
}
func RunLoadConfig(t *testing.T) {
var err error
core.Configs, err = core.LoadConfig()
core.Configs, err = core.LoadConfig(dir)
t.Log(core.Configs)
assert.Nil(t, err)
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) {
var err error
core.CoreApp, err = core.SelectCore()
if err != nil {
t.FailNow()
}
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.NotEmpty(t, core.CoreApp.ApiKey)
assert.NotEmpty(t, core.CoreApp.ApiSecret)
@ -270,12 +292,12 @@ func RunSelectAllMysqlServices(t *testing.T) {
var err error
services, err := core.CoreApp.SelectAllServices()
assert.Nil(t, err)
assert.Equal(t, 5, len(services))
assert.Equal(t, 18, len(services))
}
func RunSelectAllMysqlCommunications(t *testing.T) {
var err error
notifiers.Collections = core.DbSession.Collection("communication")
notifiers.Collections = core.DbSession.Table("communication").Model(&notifiers.Notification{})
comms := notifiers.Load()
assert.Nil(t, err)
assert.Equal(t, 3, len(comms))
@ -284,19 +306,19 @@ func RunSelectAllMysqlCommunications(t *testing.T) {
func RunUser_SelectAll(t *testing.T) {
users, err := core.SelectAllUsers()
assert.Nil(t, err)
assert.Equal(t, 2, len(users))
assert.Equal(t, 3, len(users))
}
func RunUser_Create(t *testing.T) {
user := core.ReturnUser(&types.User{
Username: "admin",
Password: "admin",
Email: "info@testuser.com",
Username: "hunterlong",
Password: "password123",
Email: "info@gmail.com",
Admin: true,
})
id, err := user.Create()
assert.Nil(t, err)
assert.Equal(t, int64(1), id)
assert.Equal(t, int64(2), id)
user2 := core.ReturnUser(&types.User{
Username: "superadmin",
Password: "admin",
@ -305,7 +327,7 @@ func RunUser_Create(t *testing.T) {
})
id, err = user2.Create()
assert.Nil(t, err)
assert.Equal(t, int64(2), id)
assert.Equal(t, int64(3), id)
}
func RunUser_Update(t *testing.T) {
@ -342,7 +364,10 @@ func RunSelectAllServices(t *testing.T) {
var err error
services, err := core.CoreApp.SelectAllServices()
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) {
@ -365,8 +390,7 @@ func RunService_Create(t *testing.T) {
})
id, err := service.Create()
assert.Nil(t, err)
assert.Equal(t, int64(6), id)
t.Log(service)
assert.Equal(t, int64(19), id)
}
func RunService_ToJSON(t *testing.T) {
@ -379,15 +403,20 @@ func RunService_ToJSON(t *testing.T) {
func RunService_AvgTime(t *testing.T) {
service := core.SelectService(1)
assert.NotNil(t, service)
avg := service.AvgUptime()
avg := service.AvgUptime24()
assert.Equal(t, "100", avg)
}
func RunService_Online24(t *testing.T) {
service := core.SelectService(1)
assert.NotNil(t, service)
online := service.Online24()
assert.Equal(t, float32(100), online)
online := service.OnlineSince(SERVICE_SINCE)
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) {
@ -413,13 +442,13 @@ func RunBadService_Create(t *testing.T) {
})
id, err := service.Create()
assert.Nil(t, err)
assert.Equal(t, int64(7), id)
assert.Equal(t, int64(20), id)
}
func RunBadService_Check(t *testing.T) {
service := core.SelectService(7)
service := core.SelectService(18)
assert.NotNil(t, service)
assert.Equal(t, "Bad Service", service.Name)
assert.Equal(t, "Failing URL", service.Name)
for i := 0; i <= 10; i++ {
service.Check(true)
}
@ -431,9 +460,7 @@ func RunDeleteService(t *testing.T) {
assert.NotNil(t, service)
assert.Equal(t, "JSON API Tester", service.Name)
assert.True(t, service.IsRunning())
t.Log(service.Running)
err := service.Delete()
t.Log(service.Running)
assert.False(t, service.IsRunning())
assert.Nil(t, err)
}
@ -441,13 +468,10 @@ func RunDeleteService(t *testing.T) {
func RunCreateService_Hits(t *testing.T) {
services := core.CoreApp.Services()
assert.NotNil(t, services)
assert.Equal(t, 6, len(services))
for i := 0; i <= 15; i++ {
for _, s := range services {
var service *core.Service
service = s.Check(true)
assert.NotNil(t, service)
}
assert.Equal(t, 19, len(services))
for _, s := range services {
service := s.Check(true)
assert.NotNil(t, service)
}
}
@ -460,10 +484,10 @@ func RunService_Hits(t *testing.T) {
}
func RunService_Failures(t *testing.T) {
service := core.SelectService(7)
service := core.SelectService(18)
assert.NotNil(t, service)
assert.Equal(t, "Bad Service", service.Name)
assert.NotEmpty(t, service.Failures)
assert.Equal(t, "Failing URL", service.Name)
assert.NotEmpty(t, service.AllFailures())
}
func RunService_LimitedHits(t *testing.T) {
@ -479,7 +503,7 @@ func RunIndexHandler(t *testing.T) {
assert.Nil(t, err)
rr := httptest.NewRecorder()
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"))
}
@ -499,7 +523,7 @@ func RunPrometheusHandler(t *testing.T) {
rr := httptest.NewRecorder()
route.ServeHTTP(rr, req)
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))
}
@ -515,7 +539,7 @@ func RunFailingPrometheusHandler(t *testing.T) {
func RunLoginHandler(t *testing.T) {
form := url.Values{}
form.Add("username", "admin")
form.Add("password", "admin")
form.Add("password", "password123")
req, err := http.NewRequest("POST", "/dashboard", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
assert.Nil(t, err)

View File

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

View File

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

View File

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

View File

@ -34,10 +34,10 @@ type Core struct {
}
var (
Configs *types.Config
CoreApp *Core
SetupMode bool
VERSION string
Configs *DbConfig // Configs holds all of the config.yml and database info
CoreApp *Core // CoreApp is a global variable that contains many elements
SetupMode bool // SetupMode will be true if Statup does not have a database connection
VERSION string // VERSION is set on build automatically by setting a -ldflag
)
func init() {
@ -51,12 +51,6 @@ func NewCore() *Core {
return CoreApp
}
func InsertCore(c *Core) error {
col := DbSession.Collection("core")
_, err := col.Insert(c.Core)
return err
}
func (c *Core) ToCore() *types.Core {
return c.Core
}
@ -72,25 +66,27 @@ func InitApp() {
func InsertNotifierDB() error {
if DbSession == nil {
err := DbConnection(CoreApp.DbConnection, false, utils.Directory)
err := Configs.Connect(false, utils.Directory)
if err != nil {
return errors.New("database connection has not been created")
}
}
notifiers.Collections = DbSession.Collection("communication")
notifiers.Collections = commDB()
return nil
}
// UpdateCore will update the CoreApp variable inside of the 'core' table in database
func UpdateCore(c *Core) (*Core, error) {
res := DbSession.Collection("core").Find().Limit(1)
err := res.Update(c.Core)
return c, err
db := coreDB().Update(&c)
return c, db.Error
}
// UsingAssets will return true if /assets folder is present
func (c Core) UsingAssets() bool {
return source.UsingAssets(utils.Directory)
}
// SassVars opens the file /assets/scss/variables.scss to be edited in Theme
func (c Core) SassVars() string {
if !source.UsingAssets(utils.Directory) {
return ""
@ -98,6 +94,7 @@ func (c Core) SassVars() string {
return source.OpenAsset(utils.Directory, "scss/variables.scss")
}
// BaseSASS is the base design , this opens the file /assets/scss/base.scss to be edited in Theme
func (c Core) BaseSASS() string {
if !source.UsingAssets(utils.Directory) {
return ""
@ -105,6 +102,8 @@ func (c Core) BaseSASS() string {
return source.OpenAsset(utils.Directory, "scss/base.scss")
}
// MobileSASS is the -webkit responsive custom css designs. This opens the
// file /assets/scss/mobile.scss to be edited in Theme
func (c Core) MobileSASS() string {
if !source.UsingAssets(utils.Directory) {
return ""
@ -112,6 +111,7 @@ func (c Core) MobileSASS() string {
return source.OpenAsset(utils.Directory, "scss/mobile.scss")
}
// AllOnline will be true if all services are online
func (c Core) AllOnline() bool {
for _, s := range CoreApp.Services() {
if !s.Online {
@ -121,49 +121,42 @@ func (c Core) AllOnline() bool {
return true
}
func SelectLastMigration() (int64, error) {
var c *types.Core
if DbSession == nil {
return 0, errors.New("Database connection has not been created yet")
}
err := DbSession.Collection("core").Find().One(&c)
if err != nil {
return 0, err
}
return c.MigrationId, err
}
// SelectCore will return the CoreApp global variable and the settings/configs for Statup
func SelectCore() (*Core, error) {
var c *types.Core
exists := DbSession.Collection("core").Exists()
if DbSession == nil {
return nil, errors.New("database has not been initiated yet.")
}
exists := DbSession.HasTable("core")
if !exists {
return nil, errors.New("core database has not been setup yet.")
}
err := DbSession.Collection("core").Find().One(&c)
if err != nil {
return nil, err
db := coreDB().First(&CoreApp)
if db.Error != nil {
return nil, db.Error
}
CoreApp.Core = c
CoreApp.DbConnection = Configs.Connection
CoreApp.DbConnection = Configs.DbConn
CoreApp.Version = VERSION
CoreApp.SelectAllServices()
if os.Getenv("USE_CDN") == "true" {
CoreApp.UseCdn = true
}
//store = sessions.NewCookieStore([]byte(core.ApiSecret))
return CoreApp, err
return CoreApp, db.Error
}
// ServiceOrder will reorder the services based on 'order_id' (Order)
type ServiceOrder []*types.Service
func (c ServiceOrder) Len() int { return len(c) }
func (c ServiceOrder) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c ServiceOrder) Less(i, j int) bool { return c[i].Order < c[j].Order }
// Services returns each Service that is attached to this instance
func (c *Core) Services() []*Service {
var services []*Service
servs := CoreApp.GetServices()
sort.Sort(ServiceOrder(servs))
CoreApp.SetServices(servs)
for _, ser := range servs {
services = append(services, ReturnService(ser))
}

View File

@ -24,9 +24,11 @@ import (
)
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() {
@ -36,51 +38,68 @@ func init() {
}
func TestNewCore(t *testing.T) {
testCore = NewCore()
assert.NotNil(t, testCore)
testCore.Name = "Tester"
utils.DeleteFile(dir + "/config.yml")
utils.DeleteFile(dir + "/statup.db")
CoreApp = NewCore()
assert.NotNil(t, CoreApp)
CoreApp.Name = "Tester"
}
func TestDbConfig_Save(t *testing.T) {
testConfig = &DbConfig{&types.DbConfig{
var err error
Configs = &DbConfig{&types.DbConfig{
DbConn: "sqlite",
Project: "Tester",
Location: dir,
}}
err := testConfig.Save()
Configs, err = Configs.Save()
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) {
err := DbConnection(testConfig.DbConn, false, dir)
err := Configs.Connect(false, dir)
assert.Nil(t, err)
}
func TestCreateDatabase(t *testing.T) {
err := CreateDatabase()
func TestDropDatabase(t *testing.T) {
err := Configs.DropDatabase()
assert.Nil(t, err)
}
func TestInsertCore(t *testing.T) {
err := InsertCore(testCore)
func TestSeedSchemaDatabase(t *testing.T) {
err := Configs.CreateDatabase()
assert.Nil(t, err)
}
func TestMigrateDatabase(t *testing.T) {
err := Configs.MigrateDatabase()
assert.Nil(t, err)
}
func TestSeedDatabase(t *testing.T) {
_, _, err := Configs.SeedDatabase()
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) {
core, err := SelectCore()
assert.Nil(t, err)
assert.Equal(t, "Tester", core.Name)
}
func TestSampleData(t *testing.T) {
err := LoadSampleData()
assert.Nil(t, err)
}
func TestSelectLastMigration(t *testing.T) {
id, err := SelectLastMigration()
assert.Nil(t, err)
assert.NotZero(t, id)
assert.Equal(t, "Awesome Status", core.Name)
}
func TestInsertNotifierDB(t *testing.T) {

View File

@ -18,95 +18,161 @@ package core
import (
"fmt"
"github.com/go-yaml/yaml"
"github.com/hunterlong/statup/source"
"github.com/hunterlong/statup/notifiers"
"github.com/hunterlong/statup/types"
"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"
"os"
"strings"
"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 (
sqliteSettings sqlite.ConnectionURL
postgresSettings postgresql.ConnectionURL
mysqlSettings mysql.ConnectionURL
DbSession sqlbuilder.Database
currentMigration int64
DbSession *gorm.DB
)
func failuresDB() *gorm.DB {
db := DbSession.Model(&types.Failure{})
if os.Getenv("GO_ENV") == "test" {
return db.Debug()
}
return db
}
func (s *Service) allHits() *gorm.DB {
var hits []*Hit
return servicesDB().Find(s).Related(&hits)
}
func hitsDB() *gorm.DB {
db := DbSession.Model(&types.Hit{})
if os.Getenv("GO_ENV") == "test" {
return db.Debug()
}
return db
}
func servicesDB() *gorm.DB {
db := DbSession.Model(&types.Service{})
if os.Getenv("GO_ENV") == "test" {
return db.Debug()
}
return db
}
func coreDB() *gorm.DB {
db := DbSession.Table("core").Model(&CoreApp)
if os.Getenv("GO_ENV") == "test" {
return db.Debug()
}
return db
}
func usersDB() *gorm.DB {
db := DbSession.Model(&types.User{})
if os.Getenv("GO_ENV") == "test" {
return db.Debug()
}
return db
}
func commDB() *gorm.DB {
db := DbSession.Table("communication").Model(&notifiers.Notification{})
if os.Getenv("GO_ENV") == "test" {
return db.Debug()
}
return db
}
func checkinDB() *gorm.DB {
if os.Getenv("GO_ENV") == "test" {
return DbSession.Model(&types.Checkin{}).Debug()
}
return DbSession.Model(&types.Checkin{})
}
type DbConfig struct {
*types.DbConfig
}
func DbConnection(dbType string, retry bool, location string) error {
// Close shutsdown the database connection
func (db *DbConfig) Close() error {
return DbSession.DB().Close()
}
// InsertCore create the single row for the Core settings in Statup
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
}
// Connect will attempt to connect to the sqlite, postgres, or mysql database
func (db *DbConfig) Connect(retry bool, location string) error {
var err error
if dbType == "sqlite" {
sqliteSettings = sqlite.ConnectionURL{
Database: location + "/statup.db",
if DbSession != nil {
DbSession = nil
}
var conn, dbType string
dbType = Configs.DbConn
switch dbType {
case "sqlite":
conn = utils.Directory + "/statup.db"
dbType = "sqlite3"
case "mysql":
if Configs.DbPort == 0 {
Configs.DbPort = 3306
}
DbSession, err = sqlite.Open(sqliteSettings)
if err != nil {
host := fmt.Sprintf("%v:%v", Configs.DbHost, Configs.DbPort)
conn = fmt.Sprintf("%v:%v@tcp(%v)/%v?charset=utf8&parseTime=True&loc=Local", Configs.DbUser, Configs.DbPass, host, Configs.DbData)
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)
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(dbType, 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 {
fmt.Println("ERROR:", err)
return err
}
} else if dbType == "mysql" {
if Configs.Port == "" {
Configs.Port = "3306"
}
host := fmt.Sprintf("%v:%v", Configs.Host, Configs.Port)
mysqlSettings = mysql.ConnectionURL{
Database: Configs.Database,
Host: host,
User: Configs.User,
Password: Configs.Password,
Options: map[string]string{"parseTime": "true", "charset": "utf8"},
}
DbSession, err = mysql.Open(mysqlSettings)
if err != nil {
if retry {
utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host))
return waitForDb(dbType)
} else {
return err
}
}
} else {
if Configs.Port == "" {
Configs.Port = "5432"
}
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)
if err != nil {
if retry {
utils.Log(1, fmt.Sprintf("Database connection to '%v' is not available, trying again in 5 seconds...", host))
return waitForDb(dbType)
} else {
return err
}
}
}
err = DbSession.Ping()
err = DbSession.DB().Ping()
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
}
func waitForDb(dbType string) error {
func (db *DbConfig) waitForDb() error {
time.Sleep(5 * time.Second)
return DbConnection(dbType, true, utils.Directory)
return db.Connect(true, utils.Directory)
}
// DatabaseMaintence will automatically delete old records from 'failures' and 'hits'
// this function is currently set to delete records 7+ days old every 60 minutes
func DatabaseMaintence() {
for range time.Tick(60 * time.Minute) {
utils.Log(1, "Checking for database records older than 7 days...")
@ -116,14 +182,17 @@ func DatabaseMaintence() {
}
}
// DeleteAllSince will delete a specific table's records based on a time.
func DeleteAllSince(table string, date time.Time) {
sql := fmt.Sprintf("DELETE FROM %v WHERE created_at < '%v';", table, date.Format("2006-01-02"))
_, err := DbSession.Exec(db.Raw(sql))
if err != nil {
utils.Log(2, err)
db := DbSession.Raw(sql)
defer db.Close()
if db.Error != nil {
utils.Log(2, db.Error)
}
}
// Update will save the config.yml file
func (c *DbConfig) Update() error {
var err error
config, err := os.Create(utils.Directory + "/config.yml")
@ -141,162 +210,115 @@ func (c *DbConfig) Update() error {
return err
}
func (c *DbConfig) Save() error {
// Save will initially create the config.yml file
func (c *DbConfig) Save() (*DbConfig, error) {
var err error
config, err := os.Create(utils.Directory + "/config.yml")
if err != nil {
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)
if err != nil {
utils.Log(3, err)
return err
return nil, err
}
config.WriteString(string(data))
config.Close()
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()
defer config.Close()
return c, err
}
// CreateCore will initialize the global variable 'CoreApp". This global variable contains most of Statup app.
func (c *DbConfig) CreateCore() *Core {
newCore := &types.Core{
Name: c.Project,
Description: c.Description,
Config: "config.yml",
ApiKey: utils.NewSHA1Hash(9),
ApiSecret: utils.NewSHA1Hash(16),
ApiKey: c.ApiKey,
ApiSecret: c.ApiSecret,
Domain: c.Domain,
MigrationId: time.Now().Unix(),
}
col := DbSession.Collection("core")
_, err = col.Insert(newCore)
if err == nil {
db := coreDB().Create(&newCore)
if db.Error == nil {
CoreApp = &Core{Core: newCore}
}
CoreApp, err = SelectCore()
CoreApp, err := SelectCore()
if err != nil {
utils.Log(4, err)
}
CoreApp.DbConnection = c.DbConn
c.ApiKey = CoreApp.ApiKey
c.ApiSecret = CoreApp.ApiSecret
return err
return CoreApp
}
func versionHigher(migrate int64) bool {
if CoreApp.MigrationId < migrate {
return true
// SeedDatabase will insert many elements into the database. This is only ran in Dev/Test move
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, 3306, 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)
}
return false
out, outErr, err := utils.Command(cmd)
return out, outErr, err
}
func reverseSlice(s []string) []string {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
return s
}
func RunDatabaseUpgrades() error {
var err error
currentMigration, err = SelectLastMigration()
if err != nil {
return err
}
utils.Log(1, fmt.Sprintf("Checking for Database Upgrades since #%v", currentMigration))
upgrade, _ := source.SqlBox.String(CoreApp.DbConnection + "_upgrade.sql")
// parse db version and upgrade file
ups := strings.Split(upgrade, "=========================================== ")
ups = reverseSlice(ups)
var ran int
var lastMigration int64
for _, v := range ups {
if len(v) == 0 {
continue
}
vers := strings.Split(v, "\n")
lastMigration = utils.StringInt(vers[0])
data := vers[1:]
//fmt.Printf("Checking Migration from v%v to v%v - %v\n", CoreApp.Version, version, versionHigher(version))
if currentMigration >= lastMigration {
continue
}
utils.Log(1, fmt.Sprintf("Migrating Database from #%v to #%v", currentMigration, lastMigration))
for _, m := range data {
if m == "" {
continue
}
utils.Log(1, fmt.Sprintf("Running Query: %v", m))
_, err := DbSession.Exec(db.Raw(m + ";"))
ran++
if err != nil {
utils.Log(2, err)
continue
}
}
currentMigration = lastMigration
}
if ran > 0 {
utils.Log(1, fmt.Sprintf("Database Upgraded %v queries ran, current #%v", ran, currentMigration))
CoreApp, err = SelectCore()
if err != nil {
panic(err)
}
CoreApp.MigrationId = currentMigration
UpdateCore(CoreApp)
}
return err
}
func DropDatabase() error {
// DropDatabase will DROP each table Statup created
func (db *DbConfig) DropDatabase() error {
utils.Log(1, "Dropping Database Tables...")
down, err := source.SqlBox.String("down.sql")
if err != nil {
return err
}
requests := strings.Split(down, ";")
for _, request := range requests {
_, err := DbSession.Exec(request)
if err != nil {
utils.Log(2, err)
}
}
return err
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 CreateDatabase() error {
// CreateDatabase will CREATE TABLES for each of the Statup elements
func (db *DbConfig) CreateDatabase() error {
utils.Log(1, "Creating Database Tables...")
sql := "postgres_up.sql"
if CoreApp.DbConnection == "mysql" {
sql = "mysql_up.sql"
} else if CoreApp.DbConnection == "sqlite" {
sql = "sqlite_up.sql"
}
up, err := source.SqlBox.String(sql)
requests := strings.Split(up, ";")
for _, request := range requests {
_, err := DbSession.Exec(request)
if err != nil {
utils.Log(2, err)
err := DbSession.CreateTable(&types.Checkin{})
err = DbSession.Table("communication").CreateTable(&notifiers.Notification{})
err = DbSession.Table("core").CreateTable(&types.Core{})
err = DbSession.CreateTable(&types.Failure{})
err = DbSession.CreateTable(&types.Hit{})
err = DbSession.CreateTable(&types.Service{})
err = DbSession.CreateTable(&types.User{})
utils.Log(1, "Statup Database Created")
return err.Error
}
// MigrateDatabase will migrate the database structure to current version.
// This function will NOT remove previous records, tables or columns from the database.
// If this function has an issue, it will ROLLBACK to the previous state.
func (db *DbConfig) MigrateDatabase() error {
utils.Log(1, "Migrating Database Tables...")
tx := DbSession.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
if tx.Error != nil {
return tx.Error
}
//secret := NewSHA1Hash()
//db.QueryRow("INSERT INTO core (secret, version) VALUES ($1, $2);", secret, VERSION).Scan()
utils.Log(1, "Database Created")
//SampleData()
return err
tx = tx.AutoMigrate(&types.Service{}, &types.User{}, &types.Hit{}, &types.Failure{}, &types.Checkin{}).Table("core").AutoMigrate(&types.Core{}).Table("communication").AutoMigrate(&notifiers.Notification{})
if tx.Error != nil {
tx.Rollback()
utils.Log(3, fmt.Sprintf("Statup Database could not be migrated: %v", tx.Error))
return tx.Error
}
utils.Log(1, "Statup Database Migrated")
return tx.Commit().Error
}
func (c *DbConfig) Clean() *DbConfig {

View File

@ -19,12 +19,12 @@ import (
"github.com/fatih/structs"
"github.com/hunterlong/statup/notifiers"
"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 {
p.OnLoad(db)
p.OnLoad(*db)
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -36,13 +36,13 @@ func TestCreateUser(t *testing.T) {
func TestSelectAllUsers(t *testing.T) {
users, err := SelectAllUsers()
assert.Nil(t, err)
assert.Equal(t, 1, len(users))
assert.Equal(t, 2, len(users))
}
func TestSelectUser(t *testing.T) {
user, err := SelectUser(1)
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)
}
@ -50,7 +50,7 @@ func TestSelectUsername(t *testing.T) {
user, err := SelectUsername("hunter")
assert.Nil(t, err)
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)
}
@ -80,7 +80,7 @@ func TestCreateUser2(t *testing.T) {
func TestSelectAllUsersAgain(t *testing.T) {
users, err := SelectAllUsers()
assert.Nil(t, err)
assert.Equal(t, 2, len(users))
assert.Equal(t, 3, len(users))
}
func TestAuthUser(t *testing.T) {
@ -88,12 +88,12 @@ func TestAuthUser(t *testing.T) {
assert.True(t, auth)
assert.NotNil(t, user)
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)
}
func TestFailedAuthUser(t *testing.T) {
user, auth := AuthUser("hunter", "wrongpassword")
user, auth := AuthUser("hunterlong", "wrongpassword")
assert.False(t, auth)
assert.Nil(t, user)
}
@ -111,3 +111,8 @@ func TestDeleteUser(t *testing.T) {
err = user.Delete()
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() {
core.NewCore()
core.Configs = new(types.Config)
core.Configs.Connection = "sqlite"
core.Configs = new(core.DbConfig)
core.Configs.DbConn = "sqlite"
core.CoreApp.DbConnection = "sqlite"
core.CoreApp.Version = "DEV"
core.DbConnection("sqlite", false, utils.Directory)
core.Configs.Connect(false, utils.Directory)
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) {
t.SkipNow()
injectDatabase()
Clean()
}
func formatJSON(res string, out interface{}) {

View File

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

View File

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

View File

@ -16,7 +16,6 @@
package handlers
import (
"github.com/hunterlong/statup/core"
"net/http"
"strings"
)
@ -53,6 +52,6 @@ func PluginsDownloadHandler(w http.ResponseWriter, r *http.Request) {
//vars := mux.Vars(router)
//name := vars["name"]
//DownloadPlugin(name)
core.LoadConfig()
//core.LoadConfig(utils.Directory)
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))
}
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 {
var token string
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(ProcessSetupHandler)).Methods("POST")
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("/logout", http.HandlerFunc(LogoutHandler))
r.Handle("/services", http.HandlerFunc(ServicesHandler)).Methods("GET")

View File

@ -59,6 +59,7 @@ func ReorderServiceHandler(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)
decoder.Decode(&newOrder)
for _, s := range newOrder {
fmt.Println("updating: ", s.Id, " to be order_id: ", s.Order)
service := core.SelectService(s.Id)
service.Order = s.Order
service.Update(false)

View File

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

View File

@ -112,7 +112,7 @@ func (u *Email) Init() error {
if u.Enabled {
utils.Log(1, fmt.Sprintf("Loading SMTP Emailer using host: %v:%v", u.Notification.Host, u.Notification.Port))
mailer = gomail.NewDialer(u.Notification.Host, u.Notification.Port, u.Notification.Username, u.Notification.Password)
mailer = gomail.NewPlainDialer(u.Notification.Host, u.Notification.Port, u.Notification.Username, u.Notification.Password)
mailer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
go u.Run()
@ -215,7 +215,7 @@ func (u *Email) OnSave() error {
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
func (u *Email) Install() error {
inDb, err := emailer.Notification.IsInDatabase()
inDb := emailer.Notification.IsInDatabase()
if !inDb {
newNotifer, err := InsertDatabase(u.Notification)
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))
}
return err
return nil
}
func (u *Email) dialSend(email *EmailOutgoing) error {

View File

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

View File

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

View File

@ -165,7 +165,7 @@ func (u *Slack) OnSave() error {
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
func (u *Slack) Install() error {
inDb, err := slacker.Notification.IsInDatabase()
inDb := slacker.Notification.IsInDatabase()
if !inDb {
newNotifer, err := InsertDatabase(u.Notification)
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))
}
return err
return nil
}

View File

@ -179,7 +179,7 @@ func (u *Twilio) OnSave() error {
// ON SERVICE FAILURE, DO YOUR OWN FUNCTIONS
func (u *Twilio) Install() error {
inDb, err := twilio.Notification.IsInDatabase()
inDb := twilio.Notification.IsInDatabase()
if !inDb {
newNotifer, err := InsertDatabase(u.Notification)
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))
}
return err
return nil
}

View File

@ -27,7 +27,6 @@ import (
)
var (
SqlBox *rice.Box
CssBox *rice.Box
ScssBox *rice.Box
JsBox *rice.Box
@ -35,7 +34,6 @@ var (
)
func Assets() {
SqlBox = rice.MustFindBox("sql")
CssBox = rice.MustFindBox("css")
ScssBox = rice.MustFindBox("scss")
JsBox = rice.MustFindBox("js")

View File

@ -1,7 +0,0 @@
DROP TABLE IF EXISTS core;
DROP TABLE IF EXISTS hits;
DROP TABLE IF EXISTS failures;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS checkins;
DROP TABLE IF EXISTS services;
DROP TABLE IF EXISTS communication;

View File

@ -1,83 +0,0 @@
CREATE TABLE core (
name VARCHAR(50),
description text,
config VARCHAR(50),
api_key VARCHAR(50),
api_secret VARCHAR(50),
style text,
footer text,
domain text,
version VARCHAR(50),
migration_id INT(6) NOT NULL DEFAULT 0,
use_cdn BOOL NOT NULL DEFAULT '0'
);
CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password text,
email VARCHAR (50),
api_key VARCHAR(50),
api_secret VARCHAR(50),
administrator BOOL NOT NULL DEFAULT '0',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX (id),
UNIQUE (username, email)
);
CREATE TABLE services (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
domain text,
check_type text,
method VARCHAR(50),
port INT(6),
expected text,
expected_status INT(6),
check_interval int(11),
post_data text,
order_id integer default 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
timeout INT(6) DEFAULT 30,
INDEX (id)
);
CREATE TABLE hits (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
service INTEGER NOT NULL,
latency float,
created_at DATETIME,
INDEX (id, service),
FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
);
CREATE TABLE failures (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
issue text,
method text,
service INTEGER NOT NULL,
created_at DATETIME,
INDEX (id, service),
FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
);
CREATE TABLE checkins (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
service INTEGER NOT NULL,
check_interval integer,
api text,
created_at DATETIME,
INDEX (id, service),
FOREIGN KEY (service) REFERENCES services(id) ON DELETE CASCADE
);
CREATE TABLE communication (
id SERIAL PRIMARY KEY,
method text,
host text,
port integer,
username text,
password text,
var1 text,
var2 text,
api_key text,
api_secret text,
enabled BOOL NOT NULL DEFAULT '0',
removable BOOL NOT NULL DEFAULT '0',
limits integer,
created_at DATETIME
);

View File

@ -1,9 +0,0 @@
=========================================== 1534178020
UPDATE services SET order_id=0 WHERE order_id IS NULL;
=========================================== 1532068515
ALTER TABLE services ALTER COLUMN order_id integer DEFAULT 0;
ALTER TABLE services ADD COLUMN timeout integer DEFAULT 30;
=========================================== 1530841150
ALTER TABLE core ADD COLUMN use_cdn BOOL NOT NULL DEFAULT '0';
=========================================== 1
ALTER TABLE core ADD COLUMN migration_id INT(6) NOT NULL DEFAULT 0;

View File

@ -1,84 +0,0 @@
CREATE TABLE core (
name text,
description text,
config text,
api_key text,
api_secret text,
style text,
footer text,
domain text,
version text,
migration_id integer default 0,
use_cdn bool default false
);
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR (50) UNIQUE,
password text,
email VARCHAR (50) UNIQUE,
api_key text,
api_secret text,
administrator bool,
created_at TIMESTAMP
);
CREATE TABLE services (
id SERIAL PRIMARY KEY,
name text,
domain text,
check_type text,
method text,
port integer,
expected text,
expected_status integer,
check_interval integer,
post_data text,
order_id integer default 0,
timeout integer default 30,
created_at TIMESTAMP
);
CREATE TABLE hits (
id SERIAL PRIMARY KEY,
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
latency float,
created_at TIMESTAMP
);
CREATE TABLE failures (
id SERIAL PRIMARY KEY,
issue text,
method text,
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
created_at TIMESTAMP
);
CREATE TABLE checkins (
id SERIAL PRIMARY KEY,
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
check_interval integer,
api text,
created_at TIMESTAMP
);
CREATE TABLE communication (
id SERIAL PRIMARY KEY,
method text,
host text,
port integer,
username text,
password text,
var1 text,
var2 text,
api_key text,
api_secret text,
enabled boolean,
removable boolean,
limits integer,
created_at TIMESTAMP
);
CREATE INDEX idx_hits ON hits(service);
CREATE INDEX idx_failures ON failures(service);
CREATE INDEX idx_checkins ON checkins(service);

View File

@ -1,9 +0,0 @@
=========================================== 1534178020
UPDATE services SET order_id=0 WHERE order_id IS NULL;
=========================================== 1532068515
ALTER TABLE services ALTER COLUMN order_id integer DEFAULT 0;
ALTER TABLE services ADD COLUMN timeout integer DEFAULT 30;
=========================================== 1530841150
ALTER TABLE core ADD COLUMN use_cdn bool DEFAULT FALSE;
=========================================== 1
ALTER TABLE core ADD COLUMN migration_id integer default 0 NOT NULL;

View File

@ -1,86 +0,0 @@
CREATE TABLE core (
name text,
description text,
config text,
api_key text,
api_secret text,
style text,
footer text,
domain text,
version text,
migration_id integer default 0,
use_cdn bool default false
);
CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
username text NOT NULL UNIQUE,
password text,
email text,
api_key text,
api_secret text,
administrator bool,
created_at DATETIME,
UNIQUE (username, email)
);
CREATE TABLE services (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name text,
domain text,
check_type text,
method text,
port integer,
expected text,
expected_status integer,
check_interval integer,
post_data text,
order_id integer default 0,
timeout integer default 30,
created_at DATETIME
);
CREATE TABLE hits (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
latency float,
created_at DATETIME
);
CREATE TABLE failures (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
issue text,
method text,
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
created_at DATETIME
);
CREATE TABLE checkins (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
service INTEGER NOT NULL REFERENCES services(id) ON DELETE CASCADE ON UPDATE CASCADE,
check_interval integer,
api text,
created_at DATETIME
);
CREATE TABLE communication (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
method text,
host text,
port integer,
username text,
password text,
var1 text,
var2 text,
api_key text,
api_secret text,
enabled boolean,
removable boolean,
limits integer,
created_at DATETIME
);
CREATE INDEX idx_hits ON hits(service);
CREATE INDEX idx_failures ON failures(service);
CREATE INDEX idx_checkins ON checkins(service);

View File

@ -1,9 +0,0 @@
=========================================== 1534178020
UPDATE services SET order_id=0 WHERE order_id IS NULL;
=========================================== 1532068515
ALTER TABLE services ALTER COLUMN order_id integer DEFAULT 0;
ALTER TABLE services ADD COLUMN timeout integer DEFAULT 30;
=========================================== 1530841150
ALTER TABLE core ADD COLUMN use_cdn bool DEFAULT FALSE;
=========================================== 1
ALTER TABLE core ADD COLUMN migration_id integer NOT NULL DEFAULT 0;

View File

@ -1,9 +1,9 @@
{{ define "footer"}}
<div class="footer text-center mb-4">
{{ if CoreApp.Footer }}
{{ safe CoreApp.Footer }}
{{ if ne CoreApp.Footer "" }}
{{ safe CoreApp.Footer }}
{{ else }}
<a href="https://github.com/hunterlong/statup" target="_blank">Statup {{VERSION}} made with ❤️</a> | <a href="/dashboard">Dashboard</a>
{{ end }}
</div>
{{ end }}
{{ end }}

View File

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

View File

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

View File

@ -237,4 +237,4 @@
</body>
</html>
</html>

View File

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

View File

@ -1,30 +1,45 @@
package types
import "time"
import (
"sort"
"time"
)
// Core struct contains all the required fields for Statup. All application settings
// will be saved into 1 row in the 'core' table. You can use the core.CoreApp
// global variable to interact with the attributes to the application, such as services.
type Core struct {
Name string `db:"name" json:"name"`
Description string `db:"description" json:"description,omitempty"`
Config string `db:"config" json:"-"`
ApiKey string `db:"api_key" json:"-"`
ApiSecret string `db:"api_secret" json:"-"`
Style string `db:"style" json:"style,omitempty"`
Footer string `db:"footer" json:"footer,omitempty"`
Domain string `db:"domain" json:"domain,omitempty"`
Version string `db:"version" json:"version"`
MigrationId int64 `db:"migration_id" json:"migration_id,omitempty"`
UseCdn bool `db:"use_cdn" json:"using_cdn,omitempty"`
DbConnection string `json:"database"`
Started time.Time `json:"started_on"`
dbServices []*Service `json:"services,omitempty"`
Plugins []Info `json:"-"`
Repos []PluginJSON `json:"-"`
AllPlugins []PluginActions `json:"-"`
Communications []AllNotifiers `json:"-"`
CoreInterface `json:"-"`
Name string `gorm:"not null;column:name" json:"name"`
Description string `gorm:"not null;column:description" json:"description,omitempty"`
Config string `gorm:"column:config" json:"-"`
ApiKey string `gorm:"column:api_key" json:"-"`
ApiSecret string `gorm:"column:api_secret" json:"-"`
Style string `gorm:"not null;column:style" json:"style,omitempty"`
Footer string `gorm:"not null;column:footer" json:"footer,omitempty"`
Domain string `gorm:"not null;column:domain" json:"domain,omitempty"`
Version string `gorm:"column:version" json:"version"`
MigrationId int64 `gorm:"column:migration_id" json:"migration_id,omitempty"`
UseCdn bool `gorm:"column:use_cdn;default:false" json:"using_cdn,omitempty"`
CreatedAt time.Time `gorm:"column:created_at" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"`
DbConnection string `gorm:"-" json:"database"`
Started time.Time `gorm:"-" json:"started_on"`
dbServices []*Service `gorm:"-" json:"services,omitempty"`
Plugins []Info `gorm:"-" json:"-"`
Repos []PluginJSON `gorm:"-" json:"-"`
AllPlugins []PluginActions `gorm:"-" json:"-"`
Communications []AllNotifiers `gorm:"-" json:"-"`
CoreInterface `gorm:"-" json:"-"`
}
type ServiceOrder []*Service
func (c ServiceOrder) Len() int { return len(c) }
func (c ServiceOrder) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c ServiceOrder) Less(i, j int) bool { return c[i].Order < c[j].Order }
func (c *Core) SetServices(s []*Service) {
sort.Sort(ServiceOrder(c.dbServices))
c.dbServices = s
}

View File

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

View File

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

View File

@ -16,9 +16,9 @@
package types
import (
"github.com/jinzhu/gorm"
"net/http"
"time"
"upper.io/db.v3/lib/sqlbuilder"
)
type PluginInfo struct {
@ -41,7 +41,7 @@ type Info struct {
type PluginActions interface {
GetInfo() Info
GetForm() string
OnLoad(sqlbuilder.Database)
OnLoad(db gorm.DB)
SetInfo(map[string]interface{}) Info
Routes() []Routing
OnSave(map[string]interface{})
@ -61,23 +61,15 @@ type PluginActions interface {
type AllNotifiers interface{}
// Hit struct is a 'successful' ping or web response entry for a service.
type Hit struct {
Id int `db:"id,omitempty"`
Service int64 `db:"service"`
Latency float64 `db:"latency"`
CreatedAt time.Time `db:"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"`
Id int64 `gorm:"primary_key;column:id"`
Service int64 `gorm:"index;column:service"`
Latency float64 `gorm:"column:latency"`
CreatedAt time.Time `gorm:"column:created_at"`
}
// DbConfig struct is used for the database connection and creates the 'config.yml' file
type DbConfig struct {
DbConn string `yaml:"connection"`
DbHost string `yaml:"host"`

View File

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

View File

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

View File

@ -16,8 +16,11 @@
package utils
import (
"errors"
"github.com/ararog/timeago"
"io"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
@ -97,6 +100,7 @@ func FileExists(name string) bool {
}
func DeleteFile(file string) error {
Log(1, "deleting file: "+file)
err := os.Remove(file)
if err != nil {
return err
@ -107,3 +111,56 @@ func DeleteFile(file string) error {
func DeleteDirectory(directory string) error {
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
}
}
}